both new posts from vacation

This commit is contained in:
Brian Picciano 2021-05-27 15:20:39 -06:00
parent 681c5d8123
commit 1b1bc6ffd6
2 changed files with 275 additions and 0 deletions

View File

@ -0,0 +1,62 @@
---
title: >-
New Year's Resolution Vibe Check
description: >-
The not-quite-halfway progress report.
---
It's been over five months since I started my New Year's resolution, where I
committed to writing 52 blog posts by the end of the year. This week I'm on the
first vacation I've been able to take since the pandemic started, and, for lack
of anything else to really write about, am doing an almost-halfway checkup on
the whole process.
Almost immediately into the process I wished I'd set my sights a bit lower. One
post a week is a pretty intense pace, it turns out. If I were to reset the
parameters of the resolution I would probably halve the requirements, down to
26 posts in the year. One concern would be that I would be more likely to forget
to do the bi-weekly post, whereas with the current system it's coupled with my
normal work rhythm and so stays more top of mind. But I think I'd have a much
easier time (perhaps even twice as easy!), so it might balance out.
My thought in the beginning was that I could write on Friday afternoons or
Monday mornings as a bookend to working, but what's generally happened is that I
write on weekends. During the week the energy to write something up just isn't
there; writing posts is a kind of work all on its own, and I can only bring
myself to do so much work everyday.
Lately it's been particularly difficult to pump out the posts. Obviously a large
component of this is that I quickly picked all the low hanging fruit that were
on my mind when I started this resolution, but an unexpected culprit has also
appeared: seasons. When I started the resolution it was still winter, and during
the cold months it's a lot easier to stay inside and work on a computer. As the
weather warms it's been harder to find time though, in between working on the
garden and going out and doing things with friends.
Figuring out what to write about is becoming more of a challenge as well
(obviously, given the topic of this post). Ideally I'd like to post about things
I'm _doing_, rather than just talking about some topic, and for the most part
I've mostly kept to that. Constantly posting about ideas I have or opinions I
hold isn't really contributing any real work, unless the ideas or opinions are
really groundbreaking (they're not). If, on the other hand, I use the posts as a
kind of background motivation to get up and do something useful, so I can write
about what I did, then at least progress has been made on _something_.
The catch there is that I've now added an additional "thing" to do every week,
in addition to the weekly post, and, as previously covered, I just don't have
the time and energy for that. So some posts (ahem) are pretty much fluff, and I
barely have the energy for those! Yet another reason to wish I'd committed to 26
in the year, I suppose.
It hasn't been all added stress and strife though. Doing the posts _has_ caused
me to work on side projects more, and even better quite a few people I know have
given me really good feedback on what I've been doing, and some have even
started getting involved. So, in the sense of being a way to inform others about
the things I'm working on, the posts are a great success! And I've definitely
been more consistent about working on side projects this year.
I'll wrap this up and continue with my vacation. Summary: blog is more extra
work than expected, it's maybe worth it, but it would be more worth it if I
halved my pace. I'm not _going_ to halve my pace, because that's not how
resolutions work. The end.

View File

@ -0,0 +1,213 @@
---
title: >-
Visualization 4
description: >-
Birth, death, and colors.
series: viz
tags: tech art
---
<canvas id="canvas" style="padding-bottom: 2rem;" width="100%" height="100%"></canvas>
This visualization is a conglomeration of ideas from all the previous ones. On
each tick up to 20 new pixels are generated. The color of each new pixel is
based on the average color of its neighbors, plus some random drift.
Each pixel dies after a certain number of ticks, `N`. A pixel's life can be
extended by up to `8N` ticks, one for each neighbor it has which is still alive.
This mechanism accounts for the strange behavior which is seen when the
visualization first loads, but also allows for more coherent clusters of pixels
to hold together as time goes on.
The asteroid rule is also in effect in this visualization, so the top row and
bottom row pixels are neighbors of each other, and similarly for the rightmost
and leftmost column pixels.
<script type="text/javascript">
function randn(n) {
return Math.floor(Math.random() * n);
}
const canvas = document.getElementById("canvas");
const parentWidth = canvas.parentElement.offsetWidth;
const rectSize = Math.floor(parentWidth /100 /2) *2; // must be even number
console.log("rectSize", rectSize);
canvas.width = parentWidth - rectSize - (parentWidth % rectSize);
canvas.height = canvas.width * 0.75;
canvas.height -= canvas.height % rectSize;
const ctx = canvas.getContext("2d");
const w = (canvas.width / rectSize) - 1;
const h = (canvas.height / rectSize) - 1;
class Elements {
constructor() {
this.els = {};
this.diff = {};
}
_normCoord(coord) {
if (typeof coord !== 'string') coord = JSON.stringify(coord);
return coord;
}
get(coord) {
return this.els[this._normCoord(coord)];
}
getAll() {
return Object.values(this.els);
}
set(coord, el) {
this.diff[this._normCoord(coord)] = {action: "set", coord: coord, ...el};
}
unset(coord) {
this.diff[this._normCoord(coord)] = {action: "unset"};
}
drawDiff(ctx) {
for (const coordStr in this.diff) {
const el = this.diff[coordStr];
const coord = JSON.parse(coordStr);
if (el.action == "set") {
ctx.fillStyle = `hsl(${el.h}, ${el.s}, ${el.l})`;
} else {
ctx.fillStyle = `#FFF`;
}
ctx.fillRect(coord[0]*rectSize, coord[1]*rectSize, rectSize, rectSize);
}
}
applyDiff() {
for (const coordStr in this.diff) {
const el = this.diff[coordStr];
delete this.diff[coordStr];
if (el.action == "set") {
delete el.action;
this.els[coordStr] = el;
} else {
delete this.els[coordStr];
}
}
}
}
const neighbors = [
[-1, -1], [0, -1], [1, -1],
[-1, 0], /* [0, 0], */ [1, 0],
[-1, 1], [0, 1], [1, 1],
];
function neighborsOf(coord) {
return neighbors.map((n) => {
let nX = coord[0]+n[0];
let nY = coord[1]+n[1];
nX = (nX + w) % w;
nY = (nY + h) % h;
return [nX, nY];
});
}
function randEmptyNeighboringCoord(els, coord) {
const neighbors = neighborsOf(coord).sort(() => Math.random() - 0.5);
for (const nCoord of neighbors) {
if (!els.get(nCoord)) return nCoord;
}
return null;
}
function neighboringElsOf(els, coord) {
const neighboringEls = [];
for (const nCoord of neighborsOf(coord)) {
const el = els.get(nCoord);
if (el) neighboringEls.push(el);
}
return neighboringEls;
}
const drift = 30;
function newEl(nEls) {
// for each h (which can be considered as degrees around a circle) break the h
// down into x and y vectors, and add those up separately. Then find the angle
// between those two resulting vectors, and that's the "average" h value.
let x = 0;
let y = 0;
nEls.forEach((el) => {
const hRad = el.h * Math.PI / 180;
x += Math.cos(hRad);
y += Math.sin(hRad);
});
let h = Math.atan2(y, x);
h = h / Math.PI * 180;
// apply some random drift, normalize
h += (Math.random() * drift * 2) - drift;
h = (h + 360) % 360;
return {
h: h,
s: "100%",
l: "50%",
};
}
const requestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
const els = new Elements();
const maxNewElsPerTick = 20;
const deathThresh = 20;
let tick = 0;
function doTick() {
tick++;
const allEls = els.getAll().sort(() => Math.random() - 0.5);
if (allEls.length == 0) {
els.set([w/2, h/2], {
h: randn(360),
s: "100%",
l: "50%",
});
}
let newEls = 0;
for (const el of allEls) {
const nCoord = randEmptyNeighboringCoord(els, el.coord);
if (!nCoord) continue; // el has no empty neighboring spots
const nEl = newEl(neighboringElsOf(els, nCoord))
nEl.tick = tick;
els.set(nCoord, nEl);
newEls++;
if (newEls >= maxNewElsPerTick) break;
}
for (const el of allEls) {
const nEls = neighboringElsOf(els, el.coord);
if (tick - el.tick - (nEls.length * deathThresh) >= deathThresh) els.unset(el.coord);
}
els.drawDiff(ctx);
els.applyDiff();
requestAnimationFrame(doTick);
}
requestAnimationFrame(doTick);
</script>