Public
Edited
Feb 20, 2023
1 fork
Insert cell
Insert cell
Insert cell
viewof seed = Inputs.range([0,1], {value: 0, label: "Seed"});

Insert cell
biome_map = {
const context = DOM.context2d(width, height);
context.clearRect(0, 0, width, height);
console.log("seed:", geometry.next_seed);

let rng = d3.randomLcg(geometry.next_seed);
let voronoi = geometry.voronoi;

let minty = ["#1B4E3B","#267055","#3EB489","#32926F","#65B172","#84AD5F","#9FA752"]
// tundra, taiga, open boreal forest, closed boreal forest, steppe, muskeg,

let chocolate = ["#E4D4C8","#D0B49F","#A47551","#523A28"]
let dark_minty = ["#1B4E3B","#267055","#3EB489","#32926F"]
let light_minty = ["#32926F","#65B172","#84AD5F","#9FA752"]

let colors = d3.schemeSpectral[11];
let scale = d3.scaleSequential()
.domain([0, 1.0])
.interpolator(d3.interpolateWarm);

let peaks = [];
let underwater = [];
let tri_colors = [];
let on_border = [];

let all_seas = [];
let north_sea = [];
let east_sea = [];
let south_sea = [];
let west_sea = [];

let all_edge = [];
let north_edge = [];
let east_edge = [];
let south_edge = [];
let west_edge = [];

let all_corners = [];
let ne_corner = [];
let se_corner = [];
let sw_corner = [];
let nw_corner = [];

let interior = [];
for (let i = 0; i < geometry.n_cells; i++) {

let comb_value = geometry.noise_values[i];
on_border[i] = false;
let edges = Array.from(pairwise(geometry.voronoi.cellPolygon(i)));
for (const edge of edges) {
if (edge[0][0] === 0.0 && edge[1][0] === 0.0) {
all_seas.push(i);
west_sea.push(i);
on_border[i] = true;
tri_colors[i] = d3.interpolateBlues(d3.randomUniform.source(rng)(0.5,1.0)());
} else if (edge[0][1] === 0.0 && edge[1][1] === 0.0) {
all_seas.push(i);
north_sea.push(i);
on_border[i] = true;
tri_colors[i] = d3.interpolateBlues(d3.randomUniform.source(rng)(0.5,1.0)());
} else if (edge[0][0] === width && edge[1][0] === width) {
all_seas.push(i);
east_sea.push(i);
on_border[i] = true;
tri_colors[i] = d3.interpolateBlues(d3.randomUniform.source(rng)(0.5,1.0)());
} else if (edge[0][1] === height && edge[1][1] == height) {
all_seas.push(i);
south_sea.push(i);
on_border[i] = true;
tri_colors[i] = d3.interpolateBlues(d3.randomUniform.source(rng)(0.5,1.0)());
}
}
}

all_seas = _.uniq(all_seas);
west_sea = _.uniq(west_sea);
north_sea = _.uniq(north_sea);
east_sea = _.uniq(east_sea);
south_sea = _.uniq(south_sea);

let all_coasts = [];
let west_coast = [];
let north_coast = [];
let east_coast = [];
let south_coast = [];
let corners = [];

for (let i of all_seas) {
for (let j of geometry.voronoi.neighbors(i)) {
if (!all_seas.includes(j)) {
all_coasts.push(j);
if (west_sea.includes(i)) {
console.log("west coast: ",j);
west_coast.push(j);
tri_colors[j] = "red";
} else if (north_sea.includes(i)) {
console.log("north coast: ",j);
north_coast.push(j);
tri_colors[j] = "orange";
} else if (east_sea.includes(i)) {
console.log("east coast: ",j);
east_coast.push(j);
tri_colors[j] = "yellow";
} else if (south_sea.includes(i)) {
console.log("south coast: ",j);
south_coast.push(j);
tri_colors[j] = "magenta";
}
}
}
}

for (let i of all_coasts) {
if (west_coast.includes(i)) {
if (north_coast.includes(i)) {
corners.push(i);
} else if (south_coast.includes(i)) {
corners.push(i)
}
} else if (east_coast.includes(i)) {
if (north_coast.includes(i)) {
corners.push(i);
} else if (south_coast.includes(i)) {
corners.push(i)
}
}
}

for (let i of corners) {
tri_colors[i] = "violet";
}

let sea_options = [west_sea, north_sea, east_sea, south_sea];
let coast_options = [west_coast, north_coast, east_coast, south_coast];
let opposite_options = [east_coast, south_coast, west_coast, north_coast];
let remaining_coasts = [[north_coast, south_coast], [east_coast, west_coast], [north_coast, south_coast], [east_coast, west_coast]];

let selection = d3.randomInt.source(rng)(0,4)();

let select_sea = sea_options[selection];
let select_coast = coast_options[selection];
let select_opposite = opposite_options[selection];

let remaining_selection = d3.randomInt.source(rng)(0,1)();
let last_selection = remaining_selection == 0 ? 1 : 0;
let select_remaining = remaining_coasts[selection];

console.log("remaining coasts", remaining_coasts, "remaining_selection", remaining_selection, "last_selection", last_selection,"select_remaining", select_remaining)

let far_coast = select_remaining[remaining_selection];
let near_coast = select_remaining[last_selection];

for (let i of select_sea) {
tri_colors[i] = chocolate[d3.randomInt.source(rng)(0,4)()];
}

for (let i of select_coast) {
tri_colors[i] = d3.interpolateYlOrBr(d3.randomUniform.source(rng)()());
}

for (let i of select_opposite) {
tri_colors[i] = d3.interpolateGnBu(d3.randomUniform.source(rng)()());
}

for (let i of far_coast) {
tri_colors[i] = dark_minty[d3.randomInt.source(rng)(0,4)()];
}

for (let i of near_coast) {
tri_colors[i] = light_minty[d3.randomInt.source(rng)(0,4)()];
}

for (let i = 0; i < geometry.n_cells; i++) {
if (!all_seas.includes(i) && !all_coasts.includes(i)) {
interior.push(i);
tri_colors[i] = light_minty[d3.randomInt.source(rng)(0,4)()];
}
}
for (let x = 0; x < width; x+= 8) {
for (let y = 0; y < height; y += 8) {

let noise_x = perlin2(x / 20, y / 20);
let noise_y = perlin2((x+3700) / 20, (y+2900) / 20);
let nearest = geometry.delaunay.find(x + noise_x * 20, y + noise_y * 20);
let tile_color = tri_colors[nearest];

context.fillStyle = tile_color;
context.beginPath();

context.moveTo( x - 4, y - 4);
context.lineTo( x + 4, y - 4);
context.lineTo( x + 4, y + 4);
context.lineTo( x - 4, y + 4);
context.lineTo( x - 4, y - 4);
context.fill()

}
}
return context.canvas;
}
Insert cell
biome_map.addEventListener("click",function(e) {
console.log("click!",e.layerX, e.layerY);
});
Insert cell
edge_map = {
const context = DOM.context2d(width, height);
context.clearRect(0, 0, width, height);
let voronoi = geometry.voronoi;

let minty = ["#1B4E3B","#267055","#3EB489","#32926F","#65B172","#84AD5F","#9FA752"]
// tundra, taiga, open boreal forest, closed boreal forest, steppe, muskeg,

let colors = d3.schemeSpectral[11];
let scale = d3.scaleSequential()
.domain([0, 1.0])
.interpolator(d3.interpolateWarm);

let peaks = [];
let underwater = [];
let tri_colors = [];
let on_border = [];

let all_seas = [];
let north_sea = [];
let east_sea = [];
let south_sea = [];
let west_sea = [];

let all_edge = [];
let north_edge = [];
let east_edge = [];
let south_edge = [];
let west_edge = [];

let all_corners = [];
let ne_corner = [];
let se_corner = [];
let sw_corner = [];
let nw_corner = [];

let interior = [];
for (let i = 0; i < geometry.n_cells; i++) {

let comb_value = geometry.noise_values[i];
on_border[i] = false;
let edges = Array.from(pairwise(geometry.voronoi.cellPolygon(i)));
for (const edge of edges) {
if (edge[0][0] === 0.0 && edge[1][0] === 0.0) {
all_seas.push(i);
west_sea.push(i);
on_border[i] = true;
tri_colors[i] = "blue";
} else if (edge[0][1] === 0.0 && edge[1][1] === 0.0) {
all_seas.push(i);
north_sea.push(i);
on_border[i] = true;
tri_colors[i] = "teal"
} else if (edge[0][0] === width && edge[1][0] === width) {
all_seas.push(i);
east_sea.push(i);
on_border[i] = true;
tri_colors[i] = "aqua";
} else if (edge[0][1] === height && edge[1][1] == height) {
all_seas.push(i);
south_sea.push(i);
on_border[i] = true;
tri_colors[i] = "green";
}
}
}

all_seas = _.uniq(all_seas);
west_sea = _.uniq(west_sea);
north_sea = _.uniq(north_sea);
east_sea = _.uniq(east_sea);
south_sea = _.uniq(south_sea);

let all_coasts = [];
let west_coast = [];
let north_coast = [];
let east_coast = [];
let south_coast = [];
let corners = [];

for (let i of all_seas) {
for (let j of geometry.voronoi.neighbors(i)) {
if (!all_seas.includes(j)) {
all_coasts.push(j);
if (west_sea.includes(i)) {
console.log("west coast: ",j);
west_coast.push(j);
tri_colors[j] = "red";
} else if (north_sea.includes(i)) {
console.log("north coast: ",j);
north_coast.push(j);
tri_colors[j] = "orange";
} else if (east_sea.includes(i)) {
console.log("east coast: ",j);
east_coast.push(j);
tri_colors[j] = "yellow";
} else if (south_sea.includes(i)) {
console.log("south coast: ",j);
south_coast.push(j);
tri_colors[j] = "magenta";
}
}
}
}

for (let i of all_coasts) {
if (west_coast.includes(i)) {
if (north_coast.includes(i)) {
corners.push(i);
} else if (south_coast.includes(i)) {
corners.push(i)
}
} else if (east_coast.includes(i)) {
if (north_coast.includes(i)) {
corners.push(i);
} else if (south_coast.includes(i)) {
corners.push(i)
}
}
}

for (let i of corners) {
tri_colors[i] = "violet";
}

for (let i = 0; i < geometry.n_cells; i++) {
if (!all_seas.includes(i) && !all_coasts.includes(i)) {
tri_colors[i] = minty[d3.randomInt(0,7)()];
}
}
// for (let i = 0; i < geometry.n_cells; i++) {
// if (!on_border[i]) {
// tri_colors[i] = minty[d3.randomInt(0,7)()];
// }
// }

for (let x = 0; x < width; x+= 8) {
for (let y = 0; y < height; y += 8) {

let noise_x = perlin2(x / 20, y / 20);
let noise_y = perlin2((x+3700) / 20, (y+2900) / 20);
let nearest = geometry.delaunay.find(x + noise_x * 20, y + noise_y * 20);
let tile_color = tri_colors[nearest];

context.fillStyle = tile_color;
context.beginPath();

context.moveTo( x - 4, y - 4);
context.lineTo( x + 4, y - 4);
context.lineTo( x + 4, y + 4);
context.lineTo( x - 4, y + 4);
context.lineTo( x - 4, y - 4);
context.fill()

}
}
return context.canvas;
}
Insert cell
noisy_trimap = {
const context = DOM.context2d(width, height);
context.clearRect(0, 0, width, height);
let voronoi = geometry.voronoi;

let minty = ["#1B4E3B","#267055","#3EB489","#32926F","#65B172","#84AD5F","#9FA752"]
// tundra, taiga, open boreal forest, closed boreal forest, steppe, muskeg,

let colors = d3.schemeSpectral[11];
let scale = d3.scaleSequential()
.domain([0, 1.0])
.interpolator(d3.interpolateWarm);

let peaks = [];
let underwater = [];
let tri_colors = [];
let on_border = [];
for (let i = 0; i < geometry.n_cells; i++) {

let comb_value = geometry.noise_values[i];
on_border[i] = false;
let edges = Array.from(pairwise(geometry.voronoi.cellPolygon(i)));
for (const edge of edges) {
if ( (edge[0][0] === 0.0 && edge[1][0] === 0.0)
||(edge[0][1] === 0.0 && edge[1][1] === 0.0)
||(edge[0][0] === width && edge[1][0] === width)
||(edge[0][1] === height && edge[1][1] == height)
) {
console.log("found boundary!",edge);
on_border[i] = true;
}
}

if (!on_border[i]) {
tri_colors[i] = minty[d3.randomInt(0,7)()];
} else {
tri_colors[i] = d3.interpolateBlues(d3.randomUniform(0.5,1.0)());
}

if (comb_value <= params.waterline) {
underwater.push(i)
} else if (comb_value >= geometry.noise_max * 0.99) {
peaks.push(i);
}
}
let to_visit = peaks.slice();
let seen = peaks.slice();

for (let x = 0; x < width; x+= 8) {
for (let y = 0; y < height; y += 8) {

let noise_x = perlin2(x / 20, y / 20);
let noise_y = perlin2((x+3700) / 20, (y+2900) / 20);
let nearest = geometry.delaunay.find(x + noise_x * 20, y + noise_y * 20);
let tile_color = tri_colors[nearest];

context.fillStyle = tile_color;
context.beginPath();

context.moveTo( x - 4, y - 4);
context.lineTo( x + 4, y - 4);
context.lineTo( x + 4, y + 4);
context.lineTo( x - 4, y + 4);
context.lineTo( x - 4, y - 4);
context.fill()

}
}
return context.canvas;
}
Insert cell
pixel_trimap = {
const context = DOM.context2d(width, height);
context.clearRect(0, 0, width, height);
let voronoi = geometry.voronoi;

let colors = d3.schemeSpectral[11];
let scale = d3.scaleQuantize()
.domain([0, 1])
.range(palette)

let peaks = [];
let underwater = [];
let tri_colors = [];
for (let i = 0; i < geometry.n_tri; i++) {

let comb_value = geometry.noise_values[i];

tri_colors[i] = context.fillStyle = d3.schemePaired[d3.randomInt(0,12)()];

if (comb_value <= params.waterline) {
underwater.push(i)
} else if (comb_value >= geometry.noise_max * 0.99) {
peaks.push(i);
}
}
let to_visit = peaks.slice();
let seen = peaks.slice();

for (let x = 0; x < width; x+= 4) {
for (let y = 0; y < height; y += 4) {
let nearest = geometry.delaunay.find(x,y);

let tile_color = tri_colors[nearest];
// if (geometry.delaunay.hull.includes(nearest)) {
// tile_color = "blue";
// }

context.fillStyle = tile_color;
// context.strokeStyle = "black";
// context.lineWidth = 1;
context.beginPath();

context.moveTo( x - 2, y - 2);
context.lineTo( x + 2, y - 2);
context.lineTo( x + 2, y + 2);
context.lineTo( x - 2, y + 2);
context.lineTo( x - 2, y - 2);
context.fill()

}
}
return context.canvas;
}
Insert cell
trimap = {
const context = DOM.context2d(width, height);
context.clearRect(0, 0, width, height);
let voronoi = geometry.voronoi;

let colors = d3.schemeSpectral[11];
let scale = d3.scaleQuantize()
.domain([0, 1])
.range(palette)

let peaks = [];
let underwater = [];
for (let i = 0; i < geometry.n_tri; i++) {

let comb_value = geometry.noise_values[i];
if (comb_value <= params.waterline) {
underwater.push(i)
} else if (comb_value >= geometry.noise_max * 0.99) {
peaks.push(i);
}
}
let to_visit = peaks.slice();
let seen = peaks.slice();

while (true) {
if (to_visit.length == 0) {
break;
}
let next_gen = [];
for (const i of to_visit) {
let neighbors = geometry.delaunay.neighbors(i);

for (const j of neighbors) {
if (seen.includes(j)) {
continue;
} else if (!next_gen.includes(j)) {
next_gen.push(j);
}
}

let comb_value = geometry.noise_values[i];

// context.fillStyle = d3.interpolateRainbow(comb_value);
context.fillStyle = d3.schemePaired[d3.randomInt(0,12)()];
// context.strokeStyle = "black";
// context.lineWidth = 1;
context.beginPath();
geometry.delaunay.renderTriangle(i,context);
context.fill()
context.stroke()
if (!seen.includes(i)) {
seen.push(i);
}
to_visit = next_gen;
}
}
return context.canvas;
}
Insert cell
quadmap = {
const context = DOM.context2d(width, height);
context.clearRect(0, 0, width, height);
let voronoi = geometry.voronoi;

let colors = d3.schemeSpectral[11];
let scale = d3.scaleQuantize()
.domain([0, 1])
.range(palette)

let peaks = [];
let underwater = [];
for (let i = 0; i < geometry.n_cells; i++) {

let comb_value = geometry.cell_noise_values[i];
if (comb_value <= params.waterline) {
underwater.push(i)
} else if (comb_value >= geometry.cell_noise_max * 0.99) {
peaks.push(i);
}
}

let to_visit = peaks.slice();
let seen = peaks.slice();

while (true) {
if (to_visit.length == 0) {
break;
}
let next_gen = [];
for (const i of to_visit) {
let neighbors = geometry.voronoi.neighbors(i);

for (const j of neighbors) {
if (seen.includes(j)) {
continue;
} else if (!next_gen.includes(j)) {
next_gen.push(j);
}
let neighbor_edge = shared_edge(i,j);
}

if (!seen.includes(i)) {
seen.push(i);
}
to_visit = next_gen;
}
}
return context.canvas;
}
Insert cell
bigmap = {
const context = DOM.context2d(width, height);
context.clearRect(0, 0, width, height);
let voronoi = geometry.voronoi;

let colors = d3.schemeSpectral[11];
let scale = d3.scaleQuantize()
.domain([0, 1])
.range(palette)

let { points, triangles } = voronoi.delaunay;
let n_tri = triangles.length / 3;

let center_x = width / 2;
let center_y = height / 2;

let dist_factor = 0.5 * Math.sqrt( (width * width) + (height * height));

let peaks = [];
let underwater = [];

console.log("geometry:", geometry);
console.log("voronoi.circumenters:", geometry.voronoi.circumcenters);
console.log("points:", points);

for (let i = 0; i < geometry.n_cells; i++) {

let comb_value = geometry.cell_noise_values[i];
if (comb_value <= params.waterline) {
underwater.push(i)
} else if (comb_value >= geometry.cell_noise_max * 0.99) {
peaks.push(i);
}
}

let to_visit = peaks.slice();
let seen = peaks.slice();

function shared_edge(a,b) {
let a_edges = Array.from(pairwise(geometry.voronoi.cellPolygon(a)));
let b_edges = Array.from(pairwise(geometry.voronoi.cellPolygon(b)));
for (const a_edge of a_edges) {
for (const b_edge of b_edges) {
if (_.isEqual(a_edge, b_edge) ||
_.isEqual(a_edge, b_edge.slice().reverse())) {
return a_edge;
}
}
}
console.log("anomaly, no edge match: ", a_edges, b_edges);
return null;
}
while (true) {
if (to_visit.length == 0) {
break;
}
let next_gen = [];
for (const i of to_visit) {
// if (peaks.includes(i)) {
// context.fillStyle = scale(0.8);
// } else if (underwater.includes(i)) {
// context.fillStyle = scale(0.2);
// } else {
// context.fillStyle = scale(geometry.cell_noise_values[i]);
// }

// context.beginPath();
// geometry.voronoi.renderCell(i,context);
// context.fill()

let i_center = [points[i*2],points[i*2 + 1]];
let neighbors = geometry.voronoi.neighbors(i);

for (const j of neighbors) {
let j_center = [points[j*2],points[j*2 + 1]];
let neighbor_edge = shared_edge(i,j);
if (neighbor_edge) {

context.beginPath();
context.fillStyle = scale(geometry.cell_noise_values[i]);
context.strokeStyle = "black";
// context.fillStyle = "none";
context.lineWidth = 1;
context.moveTo(i_center[0], i_center[1]);
context.lineTo(neighbor_edge[0][0], neighbor_edge[0][1]);
context.lineTo(neighbor_edge[1][0], neighbor_edge[1][1]);
context.moveTo(i_center[0], i_center[1]);
context.stroke();
context.fill();

context.beginPath();
context.fillStyle = scale(geometry.cell_noise_values[j]);
context.moveTo(j_center[0], j_center[1]);
context.lineTo(neighbor_edge[0][0], neighbor_edge[0][1]);
context.lineTo(neighbor_edge[1][0], neighbor_edge[1][1]);
context.lineTo(j_center[0], j_center[1]);
context.stroke();
context.fill();
// context.moveTo(neighbor_edge[0][0], neighbor_edge[0][1]);
// context.lineTo(neighbor_edge[1][0], neighbor_edge[1][1]);
// context.moveTo(i_center[0], i_center[1]);
// context.lineTo(j_center[0], j_center[1]);
// context.stroke();
// console.log(i_center, neighbor_edge[0], j_center, neighbor_edge[1]);
// context.moveTo(neighbor_edge[0][0],neighbor_edge[0][1]);
// context.lineTo(neighbor_edge[1][0],neighbor_edge[1][1]);
// context.fill();

}
if (seen.includes(j)) {
continue;
} else if (!next_gen.includes(j)) {
next_gen.push(j);
}
}
if (!seen.includes(i)) {
seen.push(i);
}
to_visit = next_gen;
}
}
return context.canvas;
}
Insert cell
rawmap = {
const context = DOM.context2d(width, height);
context.clearRect(0, 0, width, height);
let voronoi = geometry.voronoi;

let colors = d3.schemeSpectral[11];
let scale = d3.scaleQuantize()
.domain([0, 1])
.range(palette)

let { corners, triangles } = voronoi.delaunay;
let n_tri = triangles.length / 3;

let center_x = width / 2;
let center_y = height / 2;

let dist_factor = 0.5 * Math.sqrt( (width * width) + (height * height));

for (let i = 0; i < geometry.n_cells; i++) {
let polygon = geometry.voronoi.cellPolygon(i);
let x = polygon[0][0];
let y = polygon[0][1];

let comb_value = geometry.cell_noise_values[i];
// if (comb_value <= params.waterline) {
// context.fillStyle = scale(0.2);
// } else if (comb_value <= geometry.cell_noise_max * 0.99) {
// context.fillStyle = scale(comb_value);
// } else {
// context.fillStyle = scale(0.8);
// }
context.fillStyle = d3.interpolateRainbow(comb_value);
context.beginPath();
geometry.voronoi.renderCell(i,context);
context.fill()
}

return context.canvas;
}
Insert cell
palette = ["#f7fcf0", "#e0f3db", "#ccebc5", "#a8ddb5", "#7bccc4", "#4eb3d3", "#2b8cbe", "#0868ac", "#084081"].reverse()
Insert cell
geometry = {
let rng = d3.randomLcg(seed);
let points = new FastPoissonDiskSampling({
shape: [width, height],
radius: 100,
tries: 1
},rng);
let voronoi = new d3.Delaunay(points.fill().flat()).voronoi([0, 0, width, height]);

let { corners, triangles } = voronoi.delaunay;
let n_tri = triangles.length / 3;

let center_x = width / 2;
let center_y = height / 2;

let dist_factor = 0.5 * Math.sqrt( (width * width) + (height * height));

//
let noise_values = [];

var max = 0.0;
for (let i = 0; i < n_tri; i++) {
let polygon = voronoi.delaunay.trianglePolygon(i);
let x = polygon[0][0];
let y = polygon[0][1];
let noise_value = (perlin3(x / (1.5 * params.noise_scale), y / params.noise_scale, params.t / params.speed));
let noise_value_2 = (perlin3(x / (0.3 * params.noise_scale), y / (0.2 * params.noise_scale), params.t / params.speed));

let dist = Math.sqrt( (x - center_x) * (x - center_x) + (y - center_y) * (y - center_y) );
let dist_value = 1 - (dist / dist_factor);

let cos_dist = Math.cos(dist * Math.PI * params.cos_scale / dist_factor);

let n_cos_dist = cos_dist > 0 ? cos_dist : 0.0;

let n_val = noise_value > 0 ? noise_value : 0.0;
let n_val_2 = noise_value_2 > 0 ? noise_value_2 : 0.0;

let comb_value = n_cos_dist * params.cos_gain + (n_val * 0.7 + n_val_2 * 0.4) * params.noise_gain * n_cos_dist;

if (comb_value > max) { max = comb_value; }

noise_values[i] = comb_value;
}

var cell_max = 0;
var cell_noise_values = [];

let cell_arr = Array.from(voronoi.cellPolygons());

let n_cells = cell_arr.length;
for (let i = 0; i < n_cells; i++) {
let polygon = voronoi.cellPolygon(i);
let x = polygon[0][0];
let y = polygon[0][1];

let noise_value = (perlin3(x / (1.5 * params.noise_scale), y / params.noise_scale, params.t / params.speed));
let noise_value_2 = (perlin3(x / (0.3 * params.noise_scale), y / (0.2 * params.noise_scale), params.t / params.speed));

let dist = Math.sqrt( (x - center_x) * (x - center_x) + (y - center_y) * (y - center_y) );
let dist_value = 1 - (dist / dist_factor);

let cos_dist = Math.cos(dist * Math.PI * params.cos_scale / dist_factor);

let n_cos_dist = cos_dist > 0 ? cos_dist : 0.0;

let n_val = noise_value > 0 ? noise_value : 0.0;
let n_val_2 = noise_value_2 > 0 ? noise_value_2 : 0.0;

let comb_value = n_cos_dist * params.cos_gain + (n_val * 0.7 + n_val_2 * 0.4) * params.noise_gain * n_cos_dist;

if (comb_value > cell_max) { cell_max = comb_value; }

cell_noise_values[i] = comb_value;
}

return {
n_tri: n_tri,
n_cells: n_cells,
next_seed: rng(),
points: points,
voronoi: voronoi,
delaunay: voronoi.delaunay,
noise_values: noise_values,
noise_max: max,
cell_noise_values: cell_noise_values,
cell_noise_max: cell_max
}
}
Insert cell
{
const height = 600;
const context = DOM.context2d(width, height, 1);
const image = context.createImageData(width, height);
const noise = octave(perlin2, 3);
for (let z = 0, y = 0, i = 0; y < height; ++y) {
for (let x = 0; x < width; ++x, i += 4) {
let noise_r = (noise(x / 128, y / 128) + 1);
let noise_b = (noise((x+3700) / 128, (y+2900) / 128) + 1);
if ((noise_r > noise_b) && (noise_r > 1.05)) {
image.data[i] = noise_r * 128;
} else if ((noise_b > noise_r) && noise_b > 1.05) {
image.data[i+2] = noise_b * 128;
} else if (noise_b + noise_r > 1.5) {
image.data[i+1] = (noise_b) * 128;
}
image.data[i + 3] = 256;

}
}
context.putImageData(image, 0, 0);
return context.canvas;
}
Insert cell
// const P = new Uint8Array(256);
// for (let i = 0; i < 256; ++i) P[i] = i;
// d3.shuffle(P);
P = Uint8Array.of(151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180)
Insert cell
p = {
const p = new Uint8Array(512);
for (let i = 0; i < 256; ++i) p[i] = p[i + 256] = P[i];
return p;
}
Insert cell
function lerp(t, a, b) {
return a + t * (b - a);
}
Insert cell
function fade(t) {
return t * t * t * (t * (t * 6 - 15) + 10);
}
Insert cell
function grad2(i, x, y) {
const v = i & 1 ? y : x;
return i & 2 ? -v : v;
}
Insert cell
function grad3(i, x, y, z) {
const h = i & 15;
const u = h < 8 ? x : y;
const v = h < 4 ? y : h === 12 || h === 14 ? x : z;
return (h & 1 ? -u : u) + (h & 2 ? -v : v);
}
Insert cell
function perlin2(x, y) {
const xi = Math.floor(x), yi = Math.floor(y);
const X = xi & 255, Y = yi & 255;
const u = fade(x -= xi), v = fade(y -= yi);
const A = p[X] + Y, B = p[X + 1] + Y;
return lerp(
v,
lerp(u, grad2(p[A], x, y), grad2(p[B], x - 1, y)),
lerp(u, grad2(p[A + 1], x, y - 1), grad2(p[B + 1], x - 1, y - 1))
);
}
Insert cell
function perlin3(x, y, z) {
const xi = Math.floor(x), yi = Math.floor(y), zi = Math.floor(z);
const X = xi & 255, Y = yi & 255, Z = zi & 255;
const u = fade(x -= xi), v = fade(y -= yi), w = fade(z -= zi);
const A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z;
const B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z;
return lerp(
w,
lerp(
v,
lerp(u, grad3(p[AA], x, y, z), grad3(p[BA], x - 1, y, z)),
lerp(u, grad3(p[AB], x, y - 1, z), grad3(p[BB], x - 1, y - 1, z))
),
lerp(
v,
lerp(u, grad3(p[AA + 1], x, y, z - 1), grad3(p[BA + 1], x - 1, y, z - 1)),
lerp(u, grad3(p[AB + 1], x, y - 1, z - 1), grad3(p[BB + 1], x - 1, y - 1, z - 1))
)
);
}
Insert cell
function octave(noise, octaves) {
return function(x, y, z) {
let total = 0;
let frequency = 1;
let amplitude = 1;
let value = 0;
for (let i = 0; i < octaves; ++i) {
value += noise(x * frequency, y * frequency, z * frequency) * amplitude;
total += amplitude;
amplitude *= 0.5;
frequency *= 2;
}
return value / total;
};
}
Insert cell
function * pairwise (iterable) {
const iterator = iterable[Symbol.iterator]()
let current = iterator.next()
let next = iterator.next()
while (!next.done) {
yield [current.value, next.value]
current = next
next = iterator.next()
}
}

Insert cell
height = 800
Insert cell
_ = require("lodash")
Insert cell
d3 = require("d3@^6.0")
Insert cell
FastPoissonDiskSampling = require("https://cdn.jsdelivr.net/gh/kchapelier/fast-2d-poisson-disk-sampling@1.0.3/build/fast-poisson-disk-sampling.min.js")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more