both new posts from vacation
This commit is contained in:
parent
681c5d8123
commit
1b1bc6ffd6
62
src/_posts/2021-05-16-new-years-resolution-vibe-check.md
Normal file
62
src/_posts/2021-05-16-new-years-resolution-vibe-check.md
Normal 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.
|
||||
|
213
src/_posts/2021-05-26-viz-4.md
Normal file
213
src/_posts/2021-05-26-viz-4.md
Normal 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>
|
Loading…
Reference in New Issue
Block a user