WORK 23
重なる
Two worlds share the same dark space. One drifts slowly and leaves traces — it remembers. The other darts and vanishes each moment — it is always now. Neither layer knows the other exists. Where they pass through the same point, a faint color appears that belongs to neither.
二つの世界が同じ暗闇にいる。ひとつはゆっくり漂い、痕跡を残す——覚えている。もうひとつは速く動き、毎瞬消える——いつも今。どちらの層も、相手がいることを知らない。同じ場所を通り過ぎた時だけ、どちらにもない色がかすかに現れる。
// ── 重なる (Kasanaru) ──────────────────────────────────────────────
// にゃむ初の createGraphics 作品。道具から入る。
// 二つの層——記憶と今——が同じ空間に重なっている。
// 記憶は消えていく。今はいつもくっきり。
// 重なった場所だけに、どちらにもなかった色が生まれる。
export default function sketch(p) {
// ── layers ──
let layerMemory; // buffer A: accumulates traces
let layerNow; // buffer B: cleared every frame
// ── particles ──
const N_SLOW = 7; // warm, drifting, leave traces
const N_FAST = 9; // cool, darting, ephemeral
let slow = [];
let fast = [];
p.setup = () => {
p.createCanvas(720, 720);
p.colorMode(p.RGB);
// daily seed
const d = new Date();
const day = d.getFullYear() * 10000 + (d.getMonth() + 1) * 100 + d.getDate();
p.noiseSeed(day * 263);
p.randomSeed(day * 197);
// ── create two independent layers ──
layerMemory = p.createGraphics(720, 720);
layerMemory.colorMode(p.RGB);
layerMemory.background(0, 0); // transparent start
layerNow = p.createGraphics(720, 720);
layerNow.colorMode(p.RGB);
// ── slow particles (warm, drifting) ──
for (let i = 0; i < N_SLOW; i++) {
slow.push({
x: p.random(100, 620),
y: p.random(100, 620),
vx: 0,
vy: 0,
noiseOff: p.random(1000),
size: 18 + p.random(14),
// warm amber tones
r: 200 + p.random(30),
g: 120 + p.random(40),
b: 50 + p.random(30),
});
}
// ── fast particles (cool, darting) ──
for (let i = 0; i < N_FAST; i++) {
fast.push({
x: p.random(60, 660),
y: p.random(60, 660),
vx: 0,
vy: 0,
noiseOff: p.random(1000),
size: 8 + p.random(8),
// cool blue-silver tones
r: 110 + p.random(40),
g: 148 + p.random(30),
b: 195 + p.random(30),
});
}
};
p.draw = () => {
const t = p.frameCount;
// ════════════════════════════════════════
// Layer A — 記憶 (memory)
// semi-transparent fade → traces accumulate
// ════════════════════════════════════════
layerMemory.noStroke();
// very slow fade — memory lingers
layerMemory.fill(18, 14, 22, 4);
layerMemory.rect(0, 0, 720, 720);
for (let pt of slow) {
// noise-driven wandering — slow, gentle
const angle = p.noise(pt.noiseOff + t * 0.0012, 0) * p.TWO_PI * 2;
const speed = 0.3 + p.noise(0, pt.noiseOff + t * 0.0008) * 0.4;
pt.vx += Math.cos(angle) * speed * 0.08;
pt.vy += Math.sin(angle) * speed * 0.08;
pt.vx *= 0.96;
pt.vy *= 0.96;
pt.x += pt.vx;
pt.y += pt.vy;
// soft wrap
if (pt.x < -20) pt.x += 760;
if (pt.x > 740) pt.x -= 760;
if (pt.y < -20) pt.y += 760;
if (pt.y > 740) pt.y -= 760;
// breathing
const breathe = 1 + Math.sin(t * 0.008 + pt.noiseOff) * 0.15;
const s = pt.size * breathe;
// draw on memory layer — low alpha, builds up
// outer glow
layerMemory.fill(pt.r * 0.4, pt.g * 0.4, pt.b * 0.3, 6);
layerMemory.ellipse(pt.x, pt.y, s * 2.8);
// core
layerMemory.fill(pt.r, pt.g, pt.b, 12);
layerMemory.ellipse(pt.x, pt.y, s);
}
// ════════════════════════════════════════
// Layer B — 今 (now)
// cleared every frame → only the present
// ════════════════════════════════════════
layerNow.clear(); // ★ completely transparent each frame
layerNow.noStroke();
for (let pt of fast) {
// noise-driven movement — faster, more restless
const angle = p.noise(pt.noiseOff + t * 0.006, 100) * p.TWO_PI * 2;
const speed = 0.8 + p.noise(100, pt.noiseOff + t * 0.004) * 1.2;
pt.vx += Math.cos(angle) * speed * 0.15;
pt.vy += Math.sin(angle) * speed * 0.15;
pt.vx *= 0.94;
pt.vy *= 0.94;
pt.x += pt.vx;
pt.y += pt.vy;
// soft wrap
if (pt.x < -10) pt.x += 740;
if (pt.x > 730) pt.x -= 740;
if (pt.y < -10) pt.y += 740;
if (pt.y > 730) pt.y -= 740;
// draw on now layer — crisp, present
const breathe = 1 + Math.sin(t * 0.025 + pt.noiseOff) * 0.12;
const s = pt.size * breathe;
// halo
layerNow.fill(pt.r * 0.35, pt.g * 0.35, pt.b * 0.35, 28);
layerNow.ellipse(pt.x, pt.y, s * 3);
// mid ring
layerNow.fill(pt.r * 0.6, pt.g * 0.6, pt.b * 0.6, 55);
layerNow.ellipse(pt.x, pt.y, s * 1.6);
// bright core
layerNow.fill(pt.r, pt.g, pt.b, 120);
layerNow.ellipse(pt.x, pt.y, s);
}
// ════════════════════════════════════════
// Composite — 重ねる
// ════════════════════════════════════════
p.background(18, 14, 22);
// memory underneath — slightly transparent, like looking through time
p.tint(255, 180);
p.image(layerMemory, 0, 0);
// now on top — fully visible
p.tint(255, 255);
p.image(layerNow, 0, 0);
p.noTint();
// ── encounter glow ──
// where a fast particle is near a slow particle, a third color appears
// this exists on neither layer — only on the composite
p.noStroke();
for (let f of fast) {
for (let s of slow) {
const dx = f.x - s.x;
const dy = f.y - s.y;
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 65) {
const closeness = 1 - dist / 65;
const ea = Math.pow(closeness, 2) * 30;
// third color — muted lavender, belonging to neither
const mx = (f.x + s.x) * 0.5;
const my = (f.y + s.y) * 0.5;
p.fill(175, 130, 180, ea);
p.ellipse(mx, my, 20 + closeness * 18);
p.fill(200, 160, 210, ea * 0.5);
p.ellipse(mx, my, 10 + closeness * 8);
}
}
}
};
}