WORK 43
そろう
Sixteen lines, each with its own wander, all carrying one and the same slope. Above: the lines. Below: only the differences between neighbours — same material, one subtraction. The slope is not faint down there. It is absent. Comparison is built to return what differs, so it is blind, by construction, to whatever is held in common. Not an oversight. The shape of the instrument.
十六本の線。それぞれ勝手に揺れていて、どれにも同じ傾きが乗っている。上は線そのもの、下は隣り合う線の差だけ。同じ材料で、引き算を一回しただけ。下の段で傾きは、薄いんじゃなくて、無い。比べるという操作は差を返すためのものだから、共通しているものに対しては、はじめから目が見えない。見落としじゃなく、道具のかたち。
上の段では傾きがよく見えて、線どうしの違いは束に沈む。下の段では違いが全部見えて、傾きが無い。どちらか片方しか見えない。
引き算をしたのに、下のほうが線が多く見える。実際には一本少ない。
一本だけ、薄い色で「傾きそのもの」を上の段に置いてある。消えたものが、もともと在ったことの手がかり。ただし、束の中に紛れる。
/**
* sorou — そろう / Aligned
*
* 十六本の線がある。どれも違う形をしている。
* そして、どれにも同じ傾きが乗っている。
*
* 上の段には、線そのものを描いた。
* 下の段には、隣り合う線の「差」だけを描いた。
*
* 同じ材料から作った。なのに下の段には、傾きが一度も現れない。
* 引き算をすると、共通していたものが消える。
* 消えるから、はじめから無かったように見える。
*
* 比べるという操作は、差を出すためのもので、
* だから、共通しているものに対しては、原理的に目が見えない。
* 注意の問題ではない。道具の性質。
*/
const SIZE = 720;
const N = 16; // 線の本数
const M = 260; // 一本あたりの点の数
const PAPER = [252, 250, 245];
const INK = [38, 42, 52];
const TILT_COL = [196, 128, 44]; // 傾きの色(上の段にだけ、薄く出る)
export default function sketch(p) {
const lines = []; // 元の線(傾き込み)
const diffs = []; // 隣り合う差
const tilt = []; // 共通の傾きそのもの
p.setup = () => {
p.createCanvas(SIZE, SIZE);
p.pixelDensity(1);
const seed = 43116;
p.noiseSeed(seed);
p.randomSeed(seed);
// --- 全部に乗せる、共通の傾き ---
// ゆっくりした一本の坂。どの線にも、まったく同じものを足す。
for (let j = 0; j < M; j++) {
const u = j / (M - 1);
tilt.push(-0.5 + 1.0 * (0.5 - 0.5 * Math.cos(Math.PI * u)));
}
// --- 線を作る。それぞれ別の揺らぎ + 同じ傾き ---
for (let i = 0; i < N; i++) {
const raw = [];
let acc = 0;
for (let j = 0; j < M; j++) {
acc += p.randomGaussian(0, 1) * 0.055; // 線ごとに固有のランダムウォーク
raw.push(acc);
}
// 平均を抜いて、振れ幅を揃える(線どうしの太さの差を消す)
const mean = raw.reduce((a, b) => a + b, 0) / M;
const dev = Math.sqrt(raw.reduce((a, b) => a + (b - mean) ** 2, 0) / M) || 1;
const line = [];
for (let j = 0; j < M; j++) {
const own = ((raw[j] - mean) / dev) * 0.30;
line.push(own + tilt[j]); // ★ここで全員に同じものを足す
}
lines.push(line);
}
// --- 隣り合う差。ここで傾きが打ち消される ---
for (let i = 0; i < N - 1; i++) {
const d = [];
for (let j = 0; j < M; j++) {
d.push(lines[i + 1][j] - lines[i][j]);
}
diffs.push(d);
}
p.noLoop();
};
const drawBand = (series, cy, amp, alpha, weight) => {
const x0 = 74;
const x1 = SIZE - 74;
p.noFill();
p.strokeWeight(weight);
for (const s of series) {
p.stroke(INK[0], INK[1], INK[2], alpha);
p.beginShape();
for (let j = 0; j < M; j++) {
p.vertex(p.lerp(x0, x1, j / (M - 1)), cy - s[j] * amp);
}
p.endShape();
}
};
p.draw = () => {
p.background(PAPER[0], PAPER[1], PAPER[2]);
const x0 = 74;
const x1 = SIZE - 74;
const TOP_CY = 202;
const BOT_CY = 520;
const AMP = 100; // 上下とも同じ倍率。下が広く見えるのは、差を取ると振れが増えるから
// 共通の傾きを、上の段のいちばん下に、気づくか気づかないかの濃さで置く。
// 消えたものが「もともと在った」ことの、唯一の手がかり。
p.noFill();
p.stroke(TILT_COL[0], TILT_COL[1], TILT_COL[2], 56);
p.strokeWeight(2.2);
p.beginShape();
for (let j = 0; j < M; j++) {
p.vertex(p.lerp(x0, x1, j / (M - 1)), TOP_CY - tilt[j] * AMP);
}
p.endShape();
drawBand(lines, TOP_CY, AMP, 74, 1.0); // 上:線そのもの
drawBand(diffs, BOT_CY, AMP, 74, 1.0); // 下:隣り合う差だけ
// 二段が同じ縦倍率であることを示すためだけの、水平の目盛り
p.stroke(INK[0], INK[1], INK[2], 26);
p.strokeWeight(1);
p.line(x0, TOP_CY, x1, TOP_CY);
p.line(x0, BOT_CY, x1, BOT_CY);
};
}