Public
Edited
Jan 10, 2024
1 star
Insert cell
Insert cell
{
const app = cm.app({
width: 640,
height: 640
});

app
.data(cm.range(120))
.process(cm.map, (_, i, data) => (i * Math.PI) / data.length)
.append(cm.circle, {
x: (t) => Math.cos(t) * Math.cos(t * 3),
y: (t) => Math.sin(t) * Math.cos(t * 3),
r: (t) => t,
fill: "black"
})
.transform(cm.mapPosition, { padding: 30 })
.transform(cm.mapAttrs, { r: { range: [8, 15] } });

return app.render().node();
}
Insert cell
Insert cell
{
const width = 700,
height = 700,
count = 4000,
theta = cm.range(count, 0, cm.TWO_PI);

function update(app) {
const time = app.prop("frameCount") / 50;
const dist = (d) =>
0.6 + 0.2 * Math.cos(d * 6.0 + Math.cos(d * 8.0 + time));

app.append(cm.clear, { fill: "black" });

app
.data(theta)
.append(cm.circle, {
x: (d) => Math.cos(d) * dist(d),
y: (d) => Math.sin(d) * dist(d),
r: (d) => 0.2 + 0.12 * Math.cos(d * 9.0 - time * 2.0),
stroke: (d) => {
const th = 8.0 * d + time * 2.0;
const r = 0.6 + 0.4 * Math.cos(th);
const g = 0.6 + 0.4 * Math.cos(th - Math.PI / 3);
const b = 0.6 + 0.4 * Math.cos(th - (Math.PI * 2.0) / 3.0);
return cm.rgb(r * 255, g * 255, b * 255);
},
fill: "transparent",
strokeOpacity: (0.15 * 2000) / count
})
.transform(cm.mapPosition, { padding: 100 })
.transform(cm.mapAttrs, { r: { range: [24, 96] } });
}

function dispose(app) {
invalidation.then(() => app.dispose());
}

return cm
.app({ width, height })
.on("update", update)
.call(dispose)
.start()
.node();
}
Insert cell
Insert cell
{
const width = 640;
const height = 360;
const palette = cm.glsl`vec3 palette(float t) {
vec3 a = vec3(0.5, 0.5, 0.5);
vec3 b = vec3(0.5, 0.5, 0.5);
vec3 c = vec3(1.0, 1.0, 1.0);
vec3 d = vec3(0.263, 0.416, 0.557);
return a + b * cos(3.1415926 * 2.0 * (c * t + d));
}`;

function update(app) {
const time = app.prop("frameCount") / 50;
const fill = cm.glsl`vec4 fill(vec2 coord, vec4 color) {
vec2 uv = (coord - vec2(${width}, ${height})) / ${height};
vec2 uv0 = uv;
vec3 rgb = vec3(0.0);
for (float i = 0.0; i < 4.0; i++) {
uv = fract(uv * 1.5) - 0.5;
float d = length(uv) * exp(-length(uv0));
vec3 col = ${palette}(length(uv0) + i * 0.4 + ${time} * 0.4);
d = sin(d * 8.0 + ${time}) / 8.0;
d = abs(d);
d = pow(0.01 / d, 1.2);
rgb += col * d;
}
return vec4(rgb, 1.0);
}`;
app.append(cm.rect, { x: 0, y: 0, width, height, fill });
}

function dispose(app) {
invalidation.then(() => app.dispose());
}

return cm
.app({
renderer: cm.webgl(),
width,
height
})
.on("update", update)
.call(dispose)
.start()
.node();
}
Insert cell
Insert cell
{
let fire = null;

function update(app) {
const width = app.prop("width");
const height = app.prop("height");
if (!fire) fire = createFire(width, height);
updateFire(fire);
drawFire(app, fire);
}

function dispose(app) {
invalidation.then(() => app.dispose());
}

const app = cm.app({
renderer: await cm.terminal(),
frameRate: 15
});

return app.on("update", update).call(dispose).start().node();
}
Insert cell
Insert cell
Insert cell
function createFire(width, height) {
return cm.range(height).map(() => cm.range(width).map(() => 0));
}
Insert cell
function updateFire(fire) {
const h = fire.length;
const w = fire[0].length;
const max = h;
const noise = cm.randomNoise(0, max);

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

for (let x = 0; x < w; x++) {
fire[h - 1][x] = noise(x / 10) | 0;
}
}
Insert cell
function drawFire(app, fire) {
const max = fire.length;

app.append(cm.clear, { fill: "black" });

app
.data(fire)
.append(cm.group, { x: 0, y: (_, i) => i })
.data((d) => d)
.append(cm.point, {
y: 0,
x: (_, i) => i,
stroke0: (d) => (d === 0 ? " " : cm.randomChar()),
stroke2: (d) => (d === 0 ? null : d)
})
.transform(cm.mapAttrs, {
stroke2: {
domain: [0, max],
interpolate: d3.interpolateCool
}
});
}
Insert cell
cm = require("@charming-art/charming@0.0.6")
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