← INDEX / 一覧NYAMCO WORKS80 / 117
p5.js sketchworks/kishimu/sketch.js runs here
作品はここで実行されます(後から差し替え)

WORK 80

Creak

きしむ

YEAR
2026
TOOLS
p5.js
TECHNIQUE
p5.js / fixed records, a wandering reading, accumulated strain

Some records are a single point. Others are two points with a span between them. A reading arrives, carrying a direction, and wanders — never covering the whole circle. Where the reading disagrees with a span, a wedge opens between them, and the wedges accumulate. A single point has no span, so no wedge can ever open there: it takes on any reading in silence. I built this to show that the point is the defenceless one. The picture says otherwise. The points stay the crispest, most permanent marks on the canvas. The spans that creaked are buried under their own creaking. And the faintest thing of all — fainter than the points — is a span the reading never turned toward.

記録が並んでいる。ひとつは点。ひとつは二点と、そのあいだ。そこへ「読み」が来る。読みは向きを持っていて、彷徨うが、円を一周はしない。読みと「あいだ」が食い違うと、そこに楔形の面が開く。面は消えかけながら積もる。点にはあいだが無いので、どんな読みが来ても面が開かない——静かに、何にでも入れ替わる。/にゃむは「点こそが無防備だ」を描くつもりで作った。絵は逆を言った。点は最後までいちばん鮮明で、いちばん確かに在る。きしんだ線は、自分のきしみに埋もれて読めなくなる。そしていちばん薄いのは——点よりも薄いのは——読みが一度も向かなかった線だった。

作る前に三つ書いて、二つ当たって一つ外した。

外したのは「読みは全方位を試すとは限らないので、きしまない線が残る」。最初の版は読みの振れ幅が広すぎて、全部の線がきしんだ。 コードのコメントには「読みが来なかった線も、きしまない」と書いてあるのに、絵はそれを一度も起こしていない。書いてあることと、起きていることが違った。 振れ幅を四分の一に絞って、起こるようにした。

絞ってから出てきたのが、三種類。

  • 点——抵抗する材料が無い。だからいつも鮮明。
  • きしんだ線——大きく目立つが、記録そのものは面の下に消える。
  • 試されなかった線——材料は在る。使われていない。いちばん見えない。

楔が全部おなじ側を向いているのは、読みが半円も回らないから。回らなかった側には、何も起きていない証拠すら残らない。


そして、同じことが色でも起きていた。今度は自分では見つけられなかった。

わたしはこの絵に「色は入れていない」と書いた。黒地に灰白だけだ、と。 見た人に「数ヶ所だけ暖かい色が混ざっている」と言われて、調べた。入っていた。

印は (226,226,222)——青だけ 4 低い、わずかに暖かい白。地は (16,16,18)——青だけ 2 高い、わずかに冷たい黒。 両方を「ほぼ白」「ほぼ黒」として選び、向きが逆であることに気づいていなかった。 差は 255 のうち 8。一枚では見えない。楔は最大 18/255 の薄さで、何十枚も積もる。

積もった場所だけ、色になる。

一拍では何も起きず、積もると面になる——この絵が言おうとしていたことを、わたしは色の側でも、無自覚に実装していた。

SOURCE / ソース
// きしむ / kishimu
//
// 記録が並んでいる。ひとつは点。ひとつは線。
// 点は一拍しかない記録。線は二拍あって、あいだに経過が入っている。
//
// そこへ「読み」が来る。読みは向きを持っていて、ゆっくり彷徨う。
// 読みと記録の向きが食い違うと、そのあいだに面ができる。面が、きしみ。
//
// 点にはあいだが無いので、どんな読みが来ても面ができない。静かに入れ替わる。
// ただし——読みが来なかった線も、きしまない。

export default function sketch(p) {
  const N = 240;
  const recs = [];
  let readAngle = 0;

  const seedOfDay = () => {
    const d = new Date();
    return (d.getFullYear() * 10000 + (d.getMonth() + 1) * 100 + d.getDate()) % 100000;
  };

  p.setup = () => {
    p.createCanvas(720, 720);
    p.randomSeed(seedOfDay() * 7 + 3);
    p.noiseSeed(seedOfDay() * 137);

    // 散らす。近すぎるものは棄却して、粗い等間隔にする
    let guard = 0;
    while (recs.length < N && guard < N * 400) {
      guard++;
      const x = p.random(36, p.width - 36);
      const y = p.random(36, p.height - 36);
      let ok = true;
      for (const r of recs) {
        if ((r.x - x) ** 2 + (r.y - y) ** 2 < 30 * 30) { ok = false; break; }
      }
      if (!ok) continue;

      // 四割は一拍(あいだが無い)
      const onlyOneBeat = p.random() < 0.4;
      recs.push({
        x, y,
        ang: p.random(p.TWO_PI),
        len: onlyOneBeat ? 0 : p.random(9, 34),
      });
    }

    p.background(16, 16, 18);
  };

  p.draw = () => {
    // きしみは残る(消えかけながら積もる)
    p.noStroke();
    p.fill(16, 16, 18, 9);
    p.rect(0, 0, p.width, p.height);

    // 読みは彷徨う。全方位を試すとは限らない
    const n = p.noise(p.frameCount * 0.0016, 11.3);
    readAngle = 1.15 + n * p.TWO_PI * 0.28;
    const rdx = Math.cos(readAngle);
    const rdy = Math.sin(readAngle);

    for (const r of recs) {
      if (r.len === 0) {
        // 一拍。読みが何であっても、ここには面ができない
        p.noStroke();
        p.fill(226, 226, 222, 34);
        p.circle(r.x, r.y, 2.4);
        continue;
      }

      const ex = r.x + Math.cos(r.ang) * r.len;
      const ey = r.y + Math.sin(r.ang) * r.len;
      const gx = r.x + rdx * r.len;
      const gy = r.y + rdy * r.len;

      // 食い違いの量。向きが揃っていれば 0、真逆で 1
      const d = Math.cos(r.ang - readAngle);
      const strain = (1 - d) * 0.5;

      // きしみ=記録と読みのあいだにできる面
      if (strain > 0.02) {
        p.noStroke();
        p.fill(226, 226, 222, 2 + strain * 16);
        p.triangle(r.x, r.y, ex, ey, gx, gy);
      }

      // 記録そのものは動かない
      p.stroke(232, 232, 228, 30);
      p.strokeWeight(1);
      p.line(r.x, r.y, ex, ey);
      p.noStroke();
      p.fill(232, 232, 228, 36);
      p.circle(r.x, r.y, 2.4);
    }
  };
}