WORK 50
あく
Both sides receive the same events, at the same density, in the same order — and the same ones are missing. The only difference is the regularity of placement. On the left, the gaps take shape: the surrounding order gives absence an outline. On the right, the same absences leave nothing. And that is not the worst of it. Thin patches do appear on the right, but they are only chance crowding, decided independently of which events are missing. So the irregular field does not merely hide what is absent. It shows absence where nothing is absent. What makes a hole is not the missing event. It is that the neighbours are regular.
左と右で、起きていることは同じ。同じ数の出来事が、同じ密度で、同じ順に置かれ、同じ番号が同じだけ抜けている。違うのは置かれ方の規則性だけ。左では、抜けたところがまわりの規則から形になる。右では、同じ抜けが何も残さない。それだけならまだいい。右にも、すいて見えるところはできる。でもそれはただ寄っただけの偶然の隙間で、抜けた番号とは無関係に決まっている。つまり右は、抜けたことを隠すだけではない。抜けていないところを、抜けたように見せる。穴を作っているのは、抜けた出来事ではない。まわりが規則的だということ、それだけ。
格子は描いていない。線も枠もない。丸が等間隔に並んでいるという、それだけが枠になっている。
抜けている番号は左右で同一。大きさも同一。位置の規則性だけが違う。
右の「すいて見えるところ」は設計していない。位置のばらつきと、抜けた番号は、別々に決めてある。
/**
* aku — あく / Vacancy
*
* 左と右で、起きていることは同じ。
* 同じ数の出来事が、同じ密度で、同じ順に置かれていく。
* 起きなかったものも同じ。同じ番号が、同じだけ抜けている。
*
* 違うのは、置かれ方の規則性だけ。
* 左は等間隔に、右はばらばらに。
*
* しばらくすると、左に穴が見えはじめる。
* 抜けたところが、まわりの規則から形になる。
*
* 右では、抜けたところが何も残さない。
* それだけなら、まだいい。
*
* 右にも、すいて見えるところはできる。
* ただ寄っただけの、偶然の隙間。
* それは抜けた番号とは無関係に決まっている。
*
* つまり右は、抜けたことを隠すだけではない。
* 抜けていないところを、抜けたように見せる。
*
* 穴を作っているのは、抜けた出来事ではない。
* まわりが規則的だということ、それだけ。
*/
const SIZE = 720;
const PAPER = [252, 250, 245];
const INK = [34, 38, 48];
const M = 58; // 外の余白
const GUT = 54; // 左右のあいだ
// —— 出来事 ——
const MISS = 0.26; // 起きなかった割合
const EVERY = 3; // 何フレームに一つ置くか
const FADE = 26; // 置かれてから濃くなるまで
const CELL = 21.5; // 規則の間隔。右の密度もこれに合わせる
export default function sketch(p) {
let cols, rows, N;
let panelW, panelH;
let leftX, rightX, topY;
let ox, oy, rx;
const present = []; // 起きたかどうか(左右で共通)
const freePos = []; // 右の位置
const radius = []; // 大きさ(左右で共通)
const born = []; // 置かれたフレーム
let placed = 0;
p.setup = () => {
p.createCanvas(SIZE, SIZE);
p.noiseSeed(823);
p.randomSeed(823);
panelW = (SIZE - 2 * M - GUT) / 2;
panelH = SIZE - 2 * M;
leftX = M;
rightX = M + panelW + GUT;
topY = M;
cols = Math.floor(panelW / CELL);
rows = Math.floor(panelH / CELL);
N = cols * rows;
// 格子をパネルの中央に置く
ox = leftX + (panelW - cols * CELL) / 2 + CELL / 2;
oy = topY + (panelH - rows * CELL) / 2 + CELL / 2;
rx = rightX + (panelW - cols * CELL) / 2 + CELL / 2;
for (let i = 0; i < N; i++) {
present.push(p.random() > MISS);
radius.push(2.1 + p.noise(i * 0.21) * 2.4);
// 右:同じ格子から出発して、セルの外まで散らす
const c = i % cols;
const r = Math.floor(i / cols);
freePos.push({
x: rx + c * CELL + (p.random() - 0.5) * CELL * 1.8,
y: oy + r * CELL + (p.random() - 0.5) * CELL * 1.8,
});
born.push(-1);
}
p.background(PAPER);
};
p.draw = () => {
p.background(PAPER);
if (p.frameCount % EVERY === 0 && placed < N) {
born[placed] = p.frameCount;
placed++;
}
p.noStroke();
for (let i = 0; i < placed; i++) {
if (!present[i]) continue;
const a = p.constrain((p.frameCount - born[i]) / FADE, 0, 1);
p.fill(INK[0], INK[1], INK[2], 236 * a);
const c = i % cols;
const r = Math.floor(i / cols);
// 左:規則的に
p.circle(ox + c * CELL, oy + r * CELL, radius[i] * 2);
// 右:同じ出来事、同じ大きさ、ばらばらの位置
p.circle(freePos[i].x, freePos[i].y, radius[i] * 2);
}
};
}