Public
Edited
Mar 6
Insert cell
Insert cell
{
const cols = 50;
const rows = 20;
const [cellWidth, cellHeight] = cm.measureText("M");
const width = cellWidth * cols;
const height = cellHeight * rows;
const fire = d3.range(cols * rows).map(() => 0);
const index = (x, y) => x + y * cols;

const app = cm.render({
width,
height,
loop: true,
styleBackground: "black",
frameRate: 15,
draw: () => {
const noise = cm.randomNoise(0, rows);

for (let y = 0; y < rows - 1; y++) {
for (let x = 0; x < cols; x++) {
const decay = d3.randomInt(0, 3)();
const spread = d3.randomInt(-1, 1)();
const i = Math.min(Math.max(0, x - spread), cols - 1);
const target = fire[index(i, y + 1)];
fire[index(x, y)] = Math.max(0, target - decay);
}
}

for (let x = 0; x < cols; x++) {
fire[index(x, rows - 1)] = noise(x / 10) | 0;
}

const color = d3.scaleSequential(d3.extent(fire), d3.interpolateViridis);
const fill = (d) => (d === 0 ? "transparent" : color(d));
const x = (_, i) => (i % cols) * cellWidth;
const y = (_, i) => ((i / cols) | 0) * cellHeight;

return [
cm.svg("rect", fire, {
x,
y,
fill,
stroke: fill,
width: cellWidth,
height: cellHeight
}),
cm.svg("text", fire, {
x,
y,
dy: "1.25em",
dx: "0.2em",
fontSize: 14,
fill: "white",
stroke: "white",
textContent: (d) => (d ? ch() : "")
})
];
}
});

// Dispose resources when rerunning the cell
invalidation.then(() => app.dispose());

return app.node();
}
Insert cell
function ch() {
const seed = d3.randomInt(32, 127)();
return String.fromCharCode(seed);
}
Insert cell
// cm = ({ ...extension, ...(await require("charmingjs@0.0.12")) })
Insert cell
import { extension } from "@charming-art/charming-extension"
Insert cell
cm = ({
...extension,
...(await require(await FileAttachment("charming.umd.min.js").url()))
})
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