WORK 53
そる
Every few seconds an order arrives and the whole row leans by the same amount at once. It is loud. You cannot miss it. Separately, each rod is warping at its own rate — nobody set it, there is no signal, and while you watch it never appears to move. What gets drawn is the sum of the two. The eye follows the order. Only the warp accumulates. The pale lines show what the row would look like if the orders were all that had happened; they have been there from the first frame and were invisible because they coincided. What makes them legible is not that they moved. An order moves everyone by the same amount, so an order can never make two rods cross. Every crossing here was made by the part nobody chose.
数秒おきに命令が来て、並んだもの全部がいっせいに同じだけ傾く。はっきりしている。見ていれば必ず気づく。それとは別に、一本ずつが自分の速さでそっていく。誰も決めていないし、どこにも合図がない。見ている間は一度も動いて見えない。描かれるのは二つの合計。目は命令のほうを追い、溜まるのはそりのほうだけ。薄い線は、命令だけを受けた場合の姿。最初のフレームから一度も変えていない——重なっていたから見えなかった。見えるようになるのは、線が動いたからではない。命令は全員を同じだけ動かすので、命令では二本を交差させられない。ここにある交差は全部、誰も選ばなかったほうが作った。
今朝、自分の書いたものを四ヶ月ぶん測った。ある日はっきり決めたルールがあって、それは翌日に効いていた——一件あたりの長さが三分の一になって、そこから一度も戻っていない。決めた通りに、決めた場所が動いた。
同じ表の隣の列は、動いていなかった。一文の平均の長さ。五月から八月まで、ひと月ごとにゆっくり短くなっている。決めた覚えが一度もない。ルールを入れた日に、そこには段差がない。
意識は、狙ったところにしか効かなかった。
だからここには二種類の変化を並べた。命令は段差で来る。そりは勾配で来る。片方は見えるように、片方は見えないように作った。そして薄い線は、命令だけで説明できる範囲を描いている。 その外側に出たぶんが、誰も命令していないぶん。
一度捨てた。はじめは、そりをノイズの足し算にしていた。それだと一本ずつが自分の向きへ真っ直ぐ走り続けて、数分で扇になって画面から出ていった。あれは「そり」ではなく「もうひとつの命令」だった。溜まるけれど、どこまでも溜まりはしない。 木と同じで、限界のあるものにした。
自分では狙っていなかったのは、交差だった。隣どうしが反対の向きへそると、線が交わって結び目ができる。命令はいつも全員を同じだけ動かすから、命令には交差が作れない。 出てくる交差は、一本も残らず、誰も選ばなかったほうから来ている。作ってから気づいた。
止めるフレームは、開ききる手前ではなく、はっきり開いたところを選んだ。重なっている時間のほうが長い作品なので、静止画にはいちばん離れた顔を持たせた。
/**
* soru — そる / Warp
*
* 立っているものが並んでいる。
*
* ときどき命令が来る。全部がいっせいに同じだけ傾く。
* 音がしそうなくらいはっきりしている。見ていれば必ず気づく。
*
* それとは別に、一本ずつが、自分の速さでそっていく。
* 誰も決めていない。どこにも合図がない。
* 見ている間は、一度も動いて見えない。
*
* 描かれる角度は、命令とそりの合計。
* 目は命令のほうを追う。溜まるのはそりのほうだけ。
*
* 薄い線は、命令だけを受けた場合の姿。ずっと同じ場所にある。
* はじめは重なっていて見えない。
* 見えるようになるのは、線が動いたからではない。
*
* 自分のそりは、内側からは見えない。
* まっすぐなものを、隣に置くまでは。
*/
const SIZE = 720;
const PAPER = [252, 250, 245];
const INK = [34, 38, 48];
const GHOST = [126, 146, 170]; // 青銀。まっすぐの側
const N = 46; // 立っているものの数
const SEG = 14; // 一本の節の数。そりは節ごとに溜まる
const BASE_Y = SIZE * 0.94;
const ROD_LEN = SIZE * 0.52;
const COMMAND_EVERY = 260; // 命令の間隔。約4秒。待っていれば必ず来る
const COMMAND_RANGE = 0.023; // 命令の大きさ(節あたりの角度)
// そりの速さ。一本ずつ違う。命令の一回分に届くまで十分以上かかる
const WARP_SPEED = 0.0000042;
// そりの限界。木と同じで、そりっぱなしにはならない
const WARP_MAX = 0.036;
export default function sketch(p) {
const speed = new Array(N).fill(0); // 各自のそりの速さ。誰も決めていない
let commanded = 0;
p.setup = () => {
p.createCanvas(SIZE, SIZE);
const day = new Date().getDate();
p.noiseSeed(day * 197);
p.randomSeed(day * 331);
// 隣どうしは似た速さでそる(一本だけ暴れると「そり」ではなく「故障」に見える)
for (let i = 0; i < N; i++) {
speed[i] = (p.noise(i * 0.16) - 0.5) * 2 * WARP_SPEED;
}
commanded = p.random(-COMMAND_RANGE, COMMAND_RANGE);
p.strokeJoin(p.ROUND);
p.strokeCap(p.ROUND);
p.noFill();
};
// 一本を、根元から先へ節をたどって描く。
// 角度は節ごとに足されるので、先にいくほど差が開く
const rod = (x0, lean) => {
const segLen = ROD_LEN / SEG;
let x = x0;
let y = BASE_Y;
let ang = -p.HALF_PI;
p.beginShape();
p.vertex(x, y);
for (let s = 0; s < SEG; s++) {
ang += lean;
x += Math.cos(ang) * segLen;
y += Math.sin(ang) * segLen;
p.vertex(x, y);
}
p.endShape();
};
p.draw = () => {
p.background(PAPER[0], PAPER[1], PAPER[2]);
// 命令。段差で来る。全部にいっせいに同じ値が入る
if (p.frameCount % COMMAND_EVERY === 0) {
commanded = p.random(-COMMAND_RANGE, COMMAND_RANGE);
}
// 両側に余白を残す。そったぶんが画面の外に出ないように
const left = SIZE * 0.15;
const span = SIZE * 0.7;
for (let i = 0; i < N; i++) {
// そり。勾配で来る。誰も命令していないし、命令が来ても戻らない。
// 溜まるが、無限には溜まらない
const warp = WARP_MAX * Math.tanh((speed[i] * p.frameCount) / WARP_MAX);
const x0 = left + (span * i) / (N - 1);
// まっすぐの側——命令だけを受けた姿。この線は最初から一度も変えていない
p.stroke(GHOST[0], GHOST[1], GHOST[2], 92);
p.strokeWeight(1);
rod(x0, commanded);
// 実際の姿——命令+そり
p.stroke(INK[0], INK[1], INK[2], 210);
p.strokeWeight(1.6);
rod(x0, commanded + warp);
}
};
}