memoscan
← all memos

Memo 0xe3316cd1…cc98a7 on Ethereum

Resonance drawingContext.lineJoin = 'round'; for (let i = 0; i < numStrokes; i++) { const tBase = (i + 0.3 + 0.4 * rnd()) / numStrokes; const s = tBase * totalLen; const { x, y, tx, ty } = sampleAt(s); const hairRoll = rnd(); const numHairs = hairRoll < 0.65 ? 1 : (hairRoll < 0.92 ? 2 : 3); for (let h = 0; h < numHairs; h++) { const strokeLen = baseWeight * (0.9 + 3.1 * rnd()); const baseAng = Math.atan2(ty, tx); const angJitter = (rnd() - 0.5) * 0.55; const a = baseAng + angJitter; const perpDist = (rnd() - 0.5) * (1.4 * M + baseWeight * 0.9); const px = -ty * perpDist; const py = tx * perpDist; const cosA = Math.cos(a), sinA = Math.sin(a); const cx = x + px; const cy = y + py; const x1 = cx - cosA * strokeLen / 2; const y1 = cy - sinA * strokeLen / 2; const x2 = cx + cosA * strokeLen / 2; const y2 = cy + sinA * strokeLen / 2; const variant = variants[Math.floor(rnd() * variants.length)]; const alpha = Math.floor((90 + rnd() * 130) * energyFactor); const w = baseWeight * (0.30 + 0.95 * Math.pow(rnd(), 1.35)); drawingContext.strokeStyle = `rgba(${variant.r},${variant.g},${variant.b},${alpha / 255})`; drawingContext.lineWidth = w; drawingContext.beginPath(); drawingContext.moveTo(x1, y1); drawingContext.lineTo(x2, y2); drawingContext.stroke(); } } pop(); } function drawSmoothCurve(pts) { beginShape(); curveVertex(pts[0].x, pts[0].y); for (const p of pts) curveVertex(p.x, p.y); curveVertex(pts[pts.length - 1].x, pts[pts.length - 1].y); endShape(); } function drawAnnotations(P) { const inkCol = color(P.ink); push(); stroke(red(inkCol), green(inkCol), blue(inkCol), 130); strokeWeight(0.6); drawingContext.lineCap = 'butt'; const margin = canvasSize * 0.058; const ruleY = margin * 0.6; const tickStart = margin, tickEnd = canvasSize - margin; line(tickStart, ruleY, tickEnd, ruleY); const numTicks = 24; for (let i = 0; i <= numTicks; i++) { const x = tickStart + (tickEnd - tickStart) * (i / numTicks); const tickLen = (i % 4 === 0) ? 6 : 3; line(x, ruleY - tickLen, x, ruleY); } const sbY = canvasSize - margin * 0.6; const sbX = canvasSize - margin - 80; line(sbX, sbY, sbX + 60, sbY); for (let i = 0; i <= 4; i++) { line(sbX + i * 15, sbY, sbX + i * 15, sbY - 5); } pop(); } function drawFrame(P) { const margin = canvasSize * 0.04; push(); noFill(); stroke(P.ink); strokeWeight(1); rect(margin, margin, canvasSize - 2 * margin, canvasSize - 2 * margin); stroke(red(color(P.ink)), green(color(P.ink)), blue(color(P.ink)), 90); strokeWeight(0.5); rect(margin + 6, margin + 6, canvasSize - 2 * margin - 12, canvasSize - 2 * margin - 12); pop(); } function drawInkSplatter(P) { const inkCol = color(P.ink); const r = red(inkCol), g = green(inkCol), b = blue(inkCol); push(); noStroke(); const numFine = 600; for (let i = 0; i < numFine; i++) { const u = rnd(), v = rnd(); const lf = sampleField(lowGrid, u, v); if (rnd() > Math.abs(lf) * 0.6 + 0.05) continue; const a = rrange(20, 90); fill(r, g, b, a); const sz = rrange(0.5, 1.6); circle(u * canvasSize, v * canvasSize, sz); } const numLarge = 12; for (let i = 0; i < numLarge; i++) { const u = rnd(), v = rnd(); fill(r, g, b, rrange(50, 100)); const sz = rrange(1.8, 4.5); circle(u * canvasSize, v * canvasSize, sz); if (rchance(0.6)) { fill(r, g, b, 25); circle(u * canvasSize, v * canvasSize, sz * 2.5); } } pop(); } function drawFinalOverlay(P) { const G = 384; const small = createImage(G, G); small.loadPixels(); for (let i = 0; i < G * G; i++) { const v = (rnd() - 0.5) * 12; const a = Math.abs(v); small.pixels[i * 4 + 0] = 0; small.pixels[i * 4 + 1] = 0; small.pixels[i * 4 + 2] = 0; small.pixels[i * 4 + 3] = a; } small.updatePixels(); push(); drawingContext.globalCompositeOperation = 'multiply'; drawingContext.imageSmoothingEnabled = false; image(small, 0, 0, canvasSize, canvasSize); drawingContext.imageSmoothingEnabled = true; drawingContext.globalCompositeOperation = 'source-over'; pop(); push(); const grd = drawingContext.createRadialGradient( canvasSize / 2, canvasSize / 2, canvasSize * 0.45, canvasSize / 2, canvasSize / 2, canvasSize * 0.78 ); grd.addColorStop(0, 'rgba(0,0,0,0)'); grd.addColorStop(1, 'rgba(0,0,0,0.10)'); drawingContext.fillStyle = grd; drawingContext.fillRect(0, 0, canvasSize, canvasSize); pop(); } function mousePressed() { if (seedLocked) return; // canonical on-chain piece — don't re-roll if (mouseX < 0 || mouseX > canvasSize || mouseY < 0 || mouseY > canvasSize) return; seed = Math.floor(Math.random() * 999999); location.hash = String(seed); generate(); } function keyPressed() { if (key === 's' || key === 'S') { saveCanvas('Resonance_' + seed, 'png'); } else if (key === 'p' || key === 'P') { exportPrintPng(); } else if (!seedLocked && keyCode === LEFT_ARROW) { seed = Math.max(1, seed - 1); location.hash = String(seed); generate(); } else if (!seedLocked && keyCode === RIGHT_ARROW) { seed = seed + 1; location.hash = String(seed); generate(); } } function exportPrintPng() { if (!composition) return; const screenSize = canvasSize; const screenM = M; const screenDensity = pixelDensity(); const t0 = performance.now(); console.log(`exporting ${PRINT_EXPORT_SIZE}x${PRINT_EXPORT_SIZE} print PNG...`); try { pixelDensity(PRINT_EXPORT_PIXEL_DENSITY); canvasSize = PRINT_EXPORT_SIZE; M = canvasSize / DEFAULT_SIZE; resizeCanvas(canvasSize, canvasSize); renderPaper(); renderArtwork(); saveCanvas('Resonance_' + seed, 'png'); } finally { pixelDensity(screenDensity || SCREEN_PIXEL_DENSITY); canvasSize = screenSize; M = screenM; resizeCanvas(canvasSize, canvasSize); renderPaper(); needsRender = true; redraw(); } const t1 = performance.now(); console.log(`print export ${(t1 - t0).toFixed(0)} ms`); } function windowResized() { const newSize = Math.floor(Math.min(window.innerWidth, window.innerHeight)); if (newSize !== canvasSize) { canvasSize = newSize; M = canvasSize / DEFAULT_SIZE; pixelDensity(SCREEN_PIXEL_DENSITY); resizeCanvas(canvasSize, canvasSize); if (composition) { renderPaper(); } needsRender = true; redraw(); } }