Public
Edited
Jun 5, 2024
1 star
Insert cell
Insert cell
Insert cell
Insert cell
viewof bz = {
const { seed, size, patches, nudge, wrap } = settings;
// setup sketch
const sketch = DOM.context2d(size.width, size.height);
const { canvas } = sketch;
const strip = stripper(settings)(sketch);
sketch.fillStyle = "snow";
sketch.fillRect(0, 0, canvas.width, canvas.height);

sketch.translate(nudge.x, 0); // everything else: center horizontally
// setup data
let [flip, flop] = [
Array.from({ length: patches.w }, () => 0),
Array.from({ length: patches.w }, () => 0)
];
flip[seed.x] = 1; // plant a single seed

// evolve
const evolve = ev(wrap);
for (let y = seed.y0; y < patches.h; y++) {
flip.forEach(strip(y));
// yield canvas;
flip.forEach(evolve([flip, flop]));
[flip, flop] = [flop, flip];
}

grid(settings)(sketch);

canvas.value = [flip, flop];

return canvas;
}
Insert cell
settings = {
// aspect ratio, e.g. 16:9, 4:3
const aspect = {
wide: 16,
tall: controls.tall
};

// canvas size in px
const size = {
width,
height: ((width * aspect.tall) / aspect.wide) | 0
};

// dish size in patches
const w = (width / controls.w) | 0;
const patches = {
w: w - 1 + (w % 2), // force it to be odd so we have a proper center
h: (size.height / controls.w) | 0
};

// dish size in px
const dish = {
width: patches.w * controls.w,
height: patches.h * controls.w
};

// half of any space left horizontally or vertically: allows easy centering on canvas
const nudge = {
x: (size.width - dish.width) / 2,
y: (size.height - dish.height) / 2
};

// to wrap around to the beginning at end of strip
const wrap = mod(patches.w);

// first seed x position: halfway horizontally by default
const x = ((patches.w - 1) * (1 / 2 + controls.shiftX)) | 0;
// first seed y position; lift half width up when starting full width
const y = [
0,
controls.shiftY - (patches.w / 2)|0
]
[+(controls.initial === "full width")];
const seed = {
x,
y,
y0: y + controls.shiftY
};

// patch colors
const colors = ["white", "black"];

return {
...controls,
aspect,
size,
patches,
dish,
nudge,
wrap,
seed,
colors
};
}
Insert cell
Insert cell
ruleSet =
settings.ruleValue // e.g. 90
.toString(2) // → String (7) "1011010"
.padStart(8, "0") // → String (8) "01011010" // padded left with "0"
.split("") // → Array(8) ["0", "1", "0", "1", "1", "0", "1", "0"]
.map(Number) // → Array(8) [0, 1, 0, 1, 1, 0, 1, 0]
Insert cell
ev =
(wrap) => // takes wrap around function, and returns function that…
([flip, flop]) => // takes lists of current (flip) and next (flop) generation, and returns function that…
(_,i) => // takes patch index and generates (evolves) new value and ⚠️ sets it into next
flop[i] = evolve([flip[wrap(i - 1)], flip[i], flip[wrap(i + 1)]])
Insert cell
evolve = (bitstring) => parseInt(ruleSet[7 - parseInt(bitstring.join(""), 2)])
Insert cell
evolve([0,1,1])
Insert cell
generations =
Array.from(
{length: 2**3},
(_, i) => i.toString(2).padStart(3, "0").split("").map(Number)
)
.map(triplet => ({triplet, value: evolve(triplet)}))
Insert cell
stripper =
({w, colors}) => // take settings: tile size and colors, and returns function that…
(sketch) => // takes sketch, and returns function that…
(y) => // takes y, and returns function that…
(value, x) => // takes single cell and ⚠️ fills it with appropriate color
{
sketch.fillStyle = colors[value];
sketch.fillRect(w * x, w * y, w, w);
// sketch.beginPath();
// sketch.arc(w * (x + 1/2), w * (y + 1/2), w / 2, 0, 2 * Math.PI);
// sketch.fill();
}
Insert cell
mod =
(divisor) => // takes divisor, and returns function that…
(divident) => // takes a divident and returns remainder
(divident % divisor + divisor) % divisor
Insert cell
grid =
({w, patches}) =>
(sketch) =>
{
// sketch.fillStyle = "pink";
// sketch.fillRect(0, 0, patches.w * w, patches.h * w);
sketch.lineWidth = .5 / (36/w);
sketch.strokeStyle = "grey";
d3.range(patches.w + 1).forEach((x) => {
sketch.moveTo(x * w, 0);
sketch.lineTo(x * w, patches.h * w);
});
d3.range(patches.h + 1).forEach((y) => {
sketch.moveTo(0, y * w);
sketch.lineTo(patches.w * w, y * w);
});
sketch.stroke();
}
Insert cell
import {columns} from "@martien/inputs"
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