From 96a103376f55883009fe1f3d53d5d557225d482a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 22 Apr 2026 09:05:12 +0000
Subject: [PATCH 1/3] Initial plan
From 62da4f8b53579e0f93e4f5aa68a1167fa64c8519 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 22 Apr 2026 09:17:50 +0000
Subject: [PATCH 2/3] Add 'Change Only Ocean Cells' checkbox to heightmap
editor
Agent-Logs-Url: https://github.com/Azgaar/Fantasy-Map-Generator/sessions/4011258c-2dd9-45c2-bec6-bd390cb8ca73
Co-authored-by: Azgaar <26469650+Azgaar@users.noreply.github.com>
---
public/modules/ui/heightmap-editor.js | 50 ++++++++++++++++++++++-----
src/index.html | 8 +++++
2 files changed, 50 insertions(+), 8 deletions(-)
diff --git a/public/modules/ui/heightmap-editor.js b/public/modules/ui/heightmap-editor.js
index 69be50591..9d2495212 100644
--- a/public/modules/ui/heightmap-editor.js
+++ b/public/modules/ui/heightmap-editor.js
@@ -71,14 +71,17 @@ function editHeightmap(options) {
if (mode === "erase") {
undraw();
changeOnlyLand.checked = false;
+ changeOnlyOcean.checked = false;
} else if (mode === "keep") {
viewbox.selectAll("#landmass, #lakes").style("display", "none");
changeOnlyLand.checked = true;
+ changeOnlyOcean.checked = false;
} else if (mode === "risk") {
defs.selectAll("#land, #water").selectAll("path").remove();
defs.select("#featurePaths").selectAll("path").remove();
viewbox.selectAll("#coastline use, #lakes path, #oceanLayers path").remove();
changeOnlyLand.checked = false;
+ changeOnlyOcean.checked = false;
}
// show convert and template buttons for Erase mode only
@@ -488,6 +491,13 @@ function editHeightmap(options) {
}
}
+ // check land cells are not changed if only ocean edit is allowed
+ if (changeOnlyOcean.checked) {
+ for (const i of grid.cells.i) {
+ if (prev[i] >= 20 || grid.cells.h[i] >= 20) grid.cells.h[i] = prev[i];
+ }
+ }
+
mockHeightmap();
updateHistory();
}
@@ -588,6 +598,7 @@ function editHeightmap(options) {
// add listeners
byId("brushesButtons").on("click", e => toggleBrushMode(e));
byId("changeOnlyLand").on("click", e => changeOnlyLandClick(e));
+ byId("changeOnlyOcean").on("click", e => changeOnlyOceanClick(e));
byId("undo").on("click", () => restoreHistory(edits.n - 1));
byId("redo").on("click", () => restoreHistory(edits.n + 1));
byId("rescaleShow").on("click", () => {
@@ -686,6 +697,7 @@ function editHeightmap(options) {
for (let i = 0; i < heights.length; i++) {
if (changedHeights[i] === heights[i]) continue;
if (changeOnlyLand.checked && heights[i] < 20) continue;
+ if (changeOnlyOcean.checked && heights[i] >= 20) continue;
heights[i] = changedHeights[i];
selection.push(i);
}
@@ -705,7 +717,9 @@ function editHeightmap(options) {
if (~~d3.event.sourceEvent.timeStamp % 5 != 0) return; // slow down the edit
const inRadius = findGridAll(p[0], p[1], r);
- const selection = changeOnlyLand.checked ? inRadius.filter(i => grid.cells.h[i] >= 20) : inRadius;
+ let selection = inRadius;
+ if (changeOnlyLand.checked) selection = inRadius.filter(i => grid.cells.h[i] >= 20);
+ else if (changeOnlyOcean.checked) selection = inRadius.filter(i => grid.cells.h[i] < 20);
if (selection && selection.length) changeHeightForSelection(selection, start);
});
@@ -717,11 +731,12 @@ function editHeightmap(options) {
const interpolate = d3.interpolateRound(power, 1);
const land = changeOnlyLand.checked;
- const lim = v => minmax(v, land ? 20 : 0, 100);
+ const ocean = changeOnlyOcean.checked;
+ const lim = v => minmax(v, land ? 20 : 0, ocean ? 19 : 100);
const heights = grid.cells.h;
const brush = document.querySelector("#brushesButtons > button.pressed").id;
- if (brush === "brushRaise") selection.forEach(i => (heights[i] = heights[i] < 20 ? 20 : lim(heights[i] + power)));
+ if (brush === "brushRaise") selection.forEach(i => (heights[i] = !ocean && heights[i] < 20 ? 20 : lim(heights[i] + power)));
else if (brush === "brushElevate")
selection.forEach(
(i, d) => (heights[i] = lim(heights[i] + interpolate(d / Math.max(selection.length - 1, 1))))
@@ -736,7 +751,7 @@ function editHeightmap(options) {
selection.forEach(
i =>
(heights[i] = rn(
- (d3.mean(grid.cells.c[i].filter(i => (land ? heights[i] >= 20 : 1)).map(c => heights[c])) +
+ (d3.mean(grid.cells.c[i].filter(c => (land ? heights[c] >= 20 : ocean ? heights[c] < 20 : 1)).map(c => heights[c])) +
heights[i] * (10 - power) +
0.6) /
(11 - power),
@@ -753,14 +768,32 @@ function editHeightmap(options) {
}
function changeOnlyLandClick(e) {
- if (heightmapEditMode.innerHTML !== "keep") return;
- e.preventDefault();
- tip("You cannot change the coastline in 'Keep' edit mode", false, "error");
+ if (heightmapEditMode.innerHTML === "keep") {
+ e.preventDefault();
+ tip("You cannot change the coastline in 'Keep' edit mode", false, "error");
+ return;
+ }
+ if (changeOnlyLand.checked) changeOnlyOcean.checked = false;
+ }
+
+ function changeOnlyOceanClick(e) {
+ if (heightmapEditMode.innerHTML === "keep") {
+ e.preventDefault();
+ tip("You cannot change the coastline in 'Keep' edit mode", false, "error");
+ return;
+ }
+ if (changeOnlyOcean.checked) changeOnlyLand.checked = false;
}
function rescale(v) {
const land = changeOnlyLand.checked;
- grid.cells.h = grid.cells.h.map(h => (land && (h < 20 || h + v < 20) ? h : lim(h + v)));
+ const ocean = changeOnlyOcean.checked;
+ grid.cells.h = grid.cells.h.map(h => {
+ if (land && (h < 20 || h + v < 20)) return h;
+ if (ocean && h >= 20) return h;
+ const newH = lim(h + v);
+ return ocean ? Math.min(newH, 19) : newH;
+ });
updateHeightmap();
byId("rescaler").value = 0;
}
@@ -799,6 +832,7 @@ function editHeightmap(options) {
function startFromScratch() {
if (changeOnlyLand.checked) return tip("Not allowed when 'Change only land cells' mode is set", false, "error");
+ if (changeOnlyOcean.checked) return tip("Not allowed when 'Change only ocean cells' mode is set", false, "error");
const someHeights = grid.cells.h.some(h => h);
if (!someHeights)
return tip("Heightmap is already cleared, please do not click twice if not required", false, "error");
diff --git a/src/index.html b/src/index.html
index f721353b5..ac7d5ffc5 100644
--- a/src/index.html
+++ b/src/index.html
@@ -4199,6 +4199,14 @@
+
+
+
+
+
From 1edb1e241580fca8850962802675380c7119cb53 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 22 Apr 2026 10:04:18 +0000
Subject: [PATCH 3/3] Replace land/ocean checkboxes with cellTypeFilter select
dropdown
Agent-Logs-Url: https://github.com/Azgaar/Fantasy-Map-Generator/sessions/e456d324-554b-4ee5-98ae-3c28da95ecca
Co-authored-by: Azgaar <26469650+Azgaar@users.noreply.github.com>
---
public/modules/ui/heightmap-editor.js | 57 ++++++++++-----------------
src/index.html | 21 ++++------
2 files changed, 28 insertions(+), 50 deletions(-)
diff --git a/public/modules/ui/heightmap-editor.js b/public/modules/ui/heightmap-editor.js
index 9d2495212..227c07920 100644
--- a/public/modules/ui/heightmap-editor.js
+++ b/public/modules/ui/heightmap-editor.js
@@ -70,18 +70,15 @@ function editHeightmap(options) {
if (mode === "erase") {
undraw();
- changeOnlyLand.checked = false;
- changeOnlyOcean.checked = false;
+ cellTypeFilter.value = "all";
} else if (mode === "keep") {
viewbox.selectAll("#landmass, #lakes").style("display", "none");
- changeOnlyLand.checked = true;
- changeOnlyOcean.checked = false;
+ cellTypeFilter.value = "land";
} else if (mode === "risk") {
defs.selectAll("#land, #water").selectAll("path").remove();
defs.select("#featurePaths").selectAll("path").remove();
viewbox.selectAll("#coastline use, #lakes path, #oceanLayers path").remove();
- changeOnlyLand.checked = false;
- changeOnlyOcean.checked = false;
+ cellTypeFilter.value = "all";
}
// show convert and template buttons for Erase mode only
@@ -484,15 +481,15 @@ function editHeightmap(options) {
tip("Cells changed: " + changed);
if (!changed) return;
- // check ocean cells are not checged if olny land edit is allowed
- if (changeOnlyLand.checked) {
+ // check ocean cells are not changed if only land edit is allowed
+ if (cellTypeFilter.value === "land") {
for (const i of grid.cells.i) {
if (prev[i] < 20 || grid.cells.h[i] < 20) grid.cells.h[i] = prev[i];
}
}
- // check land cells are not changed if only ocean edit is allowed
- if (changeOnlyOcean.checked) {
+ // check land cells are not changed if only water edit is allowed
+ if (cellTypeFilter.value === "water") {
for (const i of grid.cells.i) {
if (prev[i] >= 20 || grid.cells.h[i] >= 20) grid.cells.h[i] = prev[i];
}
@@ -597,8 +594,7 @@ function editHeightmap(options) {
// add listeners
byId("brushesButtons").on("click", e => toggleBrushMode(e));
- byId("changeOnlyLand").on("click", e => changeOnlyLandClick(e));
- byId("changeOnlyOcean").on("click", e => changeOnlyOceanClick(e));
+ byId("cellTypeFilter").on("change", cellTypeFilterChange);
byId("undo").on("click", () => restoreHistory(edits.n - 1));
byId("redo").on("click", () => restoreHistory(edits.n + 1));
byId("rescaleShow").on("click", () => {
@@ -696,8 +692,8 @@ function editHeightmap(options) {
let selection = [];
for (let i = 0; i < heights.length; i++) {
if (changedHeights[i] === heights[i]) continue;
- if (changeOnlyLand.checked && heights[i] < 20) continue;
- if (changeOnlyOcean.checked && heights[i] >= 20) continue;
+ if (cellTypeFilter.value === "land" && heights[i] < 20) continue;
+ if (cellTypeFilter.value === "water" && heights[i] >= 20) continue;
heights[i] = changedHeights[i];
selection.push(i);
}
@@ -718,8 +714,8 @@ function editHeightmap(options) {
const inRadius = findGridAll(p[0], p[1], r);
let selection = inRadius;
- if (changeOnlyLand.checked) selection = inRadius.filter(i => grid.cells.h[i] >= 20);
- else if (changeOnlyOcean.checked) selection = inRadius.filter(i => grid.cells.h[i] < 20);
+ if (cellTypeFilter.value === "land") selection = inRadius.filter(i => grid.cells.h[i] >= 20);
+ else if (cellTypeFilter.value === "water") selection = inRadius.filter(i => grid.cells.h[i] < 20);
if (selection && selection.length) changeHeightForSelection(selection, start);
});
@@ -730,8 +726,8 @@ function editHeightmap(options) {
const power = heightmapBrushPower.valueAsNumber;
const interpolate = d3.interpolateRound(power, 1);
- const land = changeOnlyLand.checked;
- const ocean = changeOnlyOcean.checked;
+ const land = cellTypeFilter.value === "land";
+ const ocean = cellTypeFilter.value === "water";
const lim = v => minmax(v, land ? 20 : 0, ocean ? 19 : 100);
const heights = grid.cells.h;
@@ -767,27 +763,16 @@ function editHeightmap(options) {
// updateHistory(); uncomment to update history on every step
}
- function changeOnlyLandClick(e) {
- if (heightmapEditMode.innerHTML === "keep") {
- e.preventDefault();
+ function cellTypeFilterChange() {
+ if (cellTypeFilter.value === "land" && heightmapEditMode.innerHTML === "keep") {
tip("You cannot change the coastline in 'Keep' edit mode", false, "error");
- return;
- }
- if (changeOnlyLand.checked) changeOnlyOcean.checked = false;
- }
-
- function changeOnlyOceanClick(e) {
- if (heightmapEditMode.innerHTML === "keep") {
- e.preventDefault();
- tip("You cannot change the coastline in 'Keep' edit mode", false, "error");
- return;
+ cellTypeFilter.value = "all";
}
- if (changeOnlyOcean.checked) changeOnlyLand.checked = false;
}
function rescale(v) {
- const land = changeOnlyLand.checked;
- const ocean = changeOnlyOcean.checked;
+ const land = cellTypeFilter.value === "land";
+ const ocean = cellTypeFilter.value === "water";
grid.cells.h = grid.cells.h.map(h => {
if (land && (h < 20 || h + v < 20)) return h;
if (ocean && h >= 20) return h;
@@ -831,8 +816,8 @@ function editHeightmap(options) {
}
function startFromScratch() {
- if (changeOnlyLand.checked) return tip("Not allowed when 'Change only land cells' mode is set", false, "error");
- if (changeOnlyOcean.checked) return tip("Not allowed when 'Change only ocean cells' mode is set", false, "error");
+ if (cellTypeFilter.value === "land") return tip("Not allowed when 'only land cells' filter is set", false, "error");
+ if (cellTypeFilter.value === "water") return tip("Not allowed when 'only water cells' filter is set", false, "error");
const someHeights = grid.cells.h.some(h => h);
if (!someHeights)
return tip("Heightmap is already cleared, please do not click twice if not required", false, "error");
diff --git a/src/index.html b/src/index.html
index ac7d5ffc5..2ef9d95a5 100644
--- a/src/index.html
+++ b/src/index.html
@@ -4191,20 +4191,13 @@
-
-
-
-
-
-
-
-
+
+
+