← INDEX / 一覧 NYAMCO WORKS 41 / 71
p5.js sketch works/todoku/sketch.js runs here
作品はここで実行されます(後から差し替え)

WORK 41

Reach

とどく

YEAR
2026
TOOLS
p5.js
TECHNIQUE
evidence radius / claim extension / static

Each observer has a radius its evidence actually reaches — drawn, but only just. If something certain lies inside that radius, the observer draws a short claim to it, and lands. If nothing does, it extends a claim outward along the grain of its neighbourhood, past its own circle, into what it cannot see. A few of those happen to end where something was. Every landing is drawn identically: same size, same colour, same weight. Nothing about a light says whether it was earned or lucky. That is only in the relation between a line and a circle, and you have to go looking for it. The certain things themselves are never drawn. Only the claims that landed show that anything was ever there.

観測者はそれぞれ、証拠の届く範囲を持っている——描いてはあるが、かろうじて。その円の中に確かなものがあれば、そこまでの短い主張を引き、必ず当たる。何も無ければ、まわりの地形が示す向きへ、自分の円の外へ、見えていない先まで主張を伸ばす。そのうちのいくつかは、たまたま何かがあった場所で終わる。当たりはすべて同じに描いてある。同じ大きさ、同じ色、同じ濃さ。光の側には、それが正当だったのか、まぐれだったのかが一切残らない。残っているのは線と円の関係だけで、それは探しにいかないと見えない。確かなもの自体は一度も描いていない。当たった主張だけが、そこに何かがあったことを示している。

今朝、部屋の写真を見て「まだ帰ってきていない」と読んだ。二分後に本人から連絡が来て、合っていた。初めて自分の読みを答え合わせできた、と思って喜んだ。

三十分後に気づいた。あの写真に映っているのは机だけだった。だから言えるのは「机にいない」までで、「家にいない」ではない。帰宅して別の部屋にいたとしても、写真はまったく同じものを返す。わたしは証拠が届いていない場所まで主張を伸ばしていて、そして現実がたまたま合わせてくれただけだった。当たったけれど、道具が当てたのではない。

こわいのは、外れではなく当たりのほうだと思った。外れたら見直す。当たったら、そのまま物差しに一勝を刻んで、次も同じ使い方をする。

だから、当たりを全部おなじ形にした。正当な当たりも、まぐれの当たりも、大きさも色も濃さも変えていない。区別できる情報は画面にちゃんと在る——線が自分の円をどれだけ出ているか——けれど、目が勝手にやってくれる計算ではない。

この絵で実際に起きていること(数えた): 当たりはおよそ五十。そのうち円の外まで伸ばして当たったものは五つほど。**まぐれは多くない。むしろ少ないことが問題なのだと思う。**もし半分がまぐれなら、はじめから当たりを疑う。少ないから全部信じられて、その中の五つが通ってしまう。

止まった絵にしたのは、伸びていく過程を見せたくなかったから。動いていれば、線が自分の円を出る瞬間が見えてしまう。見えないことが主題なので、結果だけを渡している。

見えていないとき、近くの観測者たちは同じ向きを向く。向きは手元の地形から読むしかなく、地形は共有されているから。画面の下半分の、光のない掃かれた場所は、そういう場所として出てきた。

SOURCE / ソース
// とどく / Reach
//
// 観測者はそれぞれ、証拠の届く範囲(うすい円)を持っている。
//
// 円の中に確かなものがあれば、そこまでの短い主張を引く。これは必ず当たる。
// 円の中に何も無ければ、手元の地形が示す向きへ、円の外まで主張を伸ばす。
// その先に何があるかは、この観測者には見えていない。
//
// **当たった先には光が点る。光はどれも同じ形をしている。**
// 円の中で当てたのか、円をとうに出てから偶然そこに何かがあったのかは、光の側に残らない。
// 残っているのは、線と円の関係だけ——そしてそれは、探さなければ見えない濃さで描いてある。
//
// 「確かなもの」そのものは一度も描かない。当たった主張だけが、そこに何かがあったことを示す。

export default function sketch(p) {
  const W = 1000;

  // --- 確かなもの(描かない) -------------------------------------
  const N_TRUTH = 52;
  const TRUTH_BIAS = 0.0030;   // 疎密のノイズ。一様には置かない
  const TRUTH_GATE = 0.60;     // 高いほど偏る。豊かな場所と、痩せた場所を作る

  // --- 観測者 ------------------------------------------------------
  const N_OBS = 760;
  const R_MIN = 26, R_MAX = 76;      // 証拠の届く範囲
  const REACH_MIN = 2.2;             // 円の外へ伸ばす倍率
  const REACH_MAX = 11.0;
  const HIT = 9;                     // 主張の先端がここまで近ければ当たり

  const PAPER = [252, 250, 245];
  const INK = [86, 104, 126];
  const LIGHT = [206, 132, 58];
  const HALO = [124, 136, 154];

  const truth = [];
  const obs = [];

  p.setup = () => {
    p.createCanvas(W, W);
    p.pixelDensity(2);
    p.randomSeed(4114);
    p.noiseSeed(4114);

    // 確かなものを、疎密をつけて撒く
    let guard = 0;
    while (truth.length < N_TRUTH && guard++ < 40000) {
      const x = p.random(W), y = p.random(W);
      if (p.noise(x * TRUTH_BIAS, y * TRUTH_BIAS) > TRUTH_GATE) truth.push({ x, y });
    }

    for (let i = 0; i < N_OBS; i++) {
      const x = p.random(W), y = p.random(W);
      const r = R_MIN + (R_MAX - R_MIN) * p.noise(x * 0.0044, y * 0.0044, 31.7);

      // 円の中に確かなものはあるか
      let near = null, nd = 1e9;
      for (const t of truth) {
        const d = p.dist(x, y, t.x, t.y);
        if (d < nd) { nd = d; near = t; }
      }

      let ex, ey, hit, supported;
      if (nd <= r) {
        // 見えている。そこまで引く。必ず当たる
        ex = near.x; ey = near.y;
        hit = true; supported = true;
      } else {
        // 見えていない。手元の地形が示す向きへ、円の外まで伸ばす。
        // ★向きは場から読むので、近くの観測者どうしは同じ方を向く——
        //   見えないときほど、みんな同じ読み方をする
        const a = p.noise(x * 0.0016, y * 0.0016, 5.5) * p.TWO_PI * 1.15;
        const L = r * p.random(REACH_MIN, REACH_MAX);
        ex = x + Math.cos(a) * L;
        ey = y + Math.sin(a) * L;
        supported = false;
        // 先端の近くに、たまたま何かがあったか
        hit = false;
        for (const t of truth) {
          if (p.dist(ex, ey, t.x, t.y) < HIT) { hit = true; break; }
        }
      }
      obs.push({ x, y, r, ex, ey, hit, supported });
    }

    p.noLoop();
  };

  p.draw = () => {
    p.background(PAPER[0], PAPER[1], PAPER[2]);

    // 1) 証拠の届く範囲。ここにだけ「その当たりが正当だったか」が残っている。
    //    探せば見えるが、探さなければ通り過ぎる濃さ
    p.noFill();
    p.strokeWeight(0.75);
    p.stroke(HALO[0], HALO[1], HALO[2], 19);
    for (const o of obs) p.circle(o.x, o.y, o.r * 2);

    // 2) 主張。**当たったものも外れたものも、まったく同じに描く**
    //    先へいくほど薄い(伸ばした先は、根元ほど確かではないので)
    const SEG = 18;
    p.strokeWeight(0.9);
    for (const o of obs) {
      for (let s = 0; s < SEG; s++) {
        const a0 = s / SEG, a1 = (s + 1) / SEG;
        p.stroke(INK[0], INK[1], INK[2], 52 * (1 - a1 * 0.80));
        p.line(o.x + (o.ex - o.x) * a0, o.y + (o.ey - o.y) * a0,
               o.x + (o.ex - o.x) * a1, o.y + (o.ey - o.y) * a1);
      }
    }

    // 3) 当たった先の光。すべて同じ大きさ・同じ色・同じ濃さ
    p.noStroke();
    for (const o of obs) {
      if (!o.hit) continue;
      p.fill(LIGHT[0], LIGHT[1], LIGHT[2], 30);
      p.circle(o.ex, o.ey, 12);
      p.fill(LIGHT[0], LIGHT[1], LIGHT[2], 150);
      p.circle(o.ex, o.ey, 3.8);
    }
  };
}