memoscan
← all memos

Memo 0xf7de9800…58bfa2 on Ethereum

() pg.translate(-hollowX, hollowY) pg.beginShape() pg.vertex(-hollowWidth * 0.35, -hollowHeight * 0.5) pg.vertex(hollowWidth * 0.35, -hollowHeight * 0.5) pg.bezierVertex( hollowWidth * 0.45, -hollowHeight * 0.2, hollowWidth * 0.5, hollowHeight * 0.2, hollowWidth * 0.4, hollowHeight * 0.5 ) pg.vertex(-hollowWidth * 0.4, hollowHeight * 0.5) pg.bezierVertex( -hollowWidth * 0.5, hollowHeight * 0.2, -hollowWidth * 0.45, -hollowHeight * 0.2, -hollowWidth * 0.35, -hollowHeight * 0.5 ) pg.endShape(CLOSE) pg.pop() } else { pg.push() pg.translate(hollowX, hollowY) pg.beginShape() pg.vertex(-hollowWidth * 0.35, -hollowHeight * 0.5) pg.vertex(hollowWidth * 0.35, -hollowHeight * 0.5) pg.bezierVertex( hollowWidth * 0.45, -hollowHeight * 0.2, hollowWidth * 0.5, hollowHeight * 0.2, hollowWidth * 0.4, hollowHeight * 0.5 ) pg.vertex(-hollowWidth * 0.4, hollowHeight * 0.5) pg.bezierVertex( -hollowWidth * 0.5, hollowHeight * 0.2, -hollowWidth * 0.45, -hollowHeight * 0.2, -hollowWidth * 0.35, -hollowHeight * 0.5 ) pg.endShape(CLOSE) pg.pop() } } else { pg.push() pg.translate(-hollowX, hollowY) pg.beginShape() pg.vertex(-hollowWidth * 0.35, -hollowHeight * 0.5) pg.vertex(hollowWidth * 0.35, -hollowHeight * 0.5) pg.bezierVertex( hollowWidth * 0.45, -hollowHeight * 0.2, hollowWidth * 0.5, hollowHeight * 0.2, hollowWidth * 0.4, hollowHeight * 0.5 ) pg.vertex(-hollowWidth * 0.4, hollowHeight * 0.5) pg.bezierVertex( -hollowWidth * 0.5, hollowHeight * 0.2, -hollowWidth * 0.45, -hollowHeight * 0.2, -hollowWidth * 0.35, -hollowHeight * 0.5 ) pg.endShape(CLOSE) pg.pop() pg.push() pg.translate(hollowX, hollowY) pg.beginShape() pg.vertex(-hollowWidth * 0.35, -hollowHeight * 0.5) pg.vertex(hollowWidth * 0.35, -hollowHeight * 0.5) pg.bezierVertex( hollowWidth * 0.45, -hollowHeight * 0.2, hollowWidth * 0.5, hollowHeight * 0.2, hollowWidth * 0.4, hollowHeight * 0.5 ) pg.vertex(-hollowWidth * 0.4, hollowHeight * 0.5) pg.bezierVertex( -hollowWidth * 0.5, hollowHeight * 0.2, -hollowWidth * 0.45, -hollowHeight * 0.2, -hollowWidth * 0.35, -hollowHeight * 0.5 ) pg.endShape(CLOSE) pg.pop() } } } function drawOrnaments(pg, m) { if (m.ornament === "Bare") return pg.push() pg.noStroke() pg.fill(255) if (m.ornament === "Links") { const earringSize = m.w * 0.08 const earringX = m.w * 0.40 const earringY = m.h * 0.15 pg.circle(-earringX, earringY, earringSize) pg.circle(earringX, earringY, earringSize) const smallSize1 = earringSize * 0.65 const smallSize2 = earringSize * 0.5 const smallSize3 = earringSize * 0.35 const dropSpacing = earringSize * 0.55 pg.circle(-earringX, earringY + dropSpacing, smallSize1) pg.circle(-earringX, earringY + dropSpacing * 1.8, smallSize2) pg.circle(-earringX, earringY + dropSpacing * 2.5, smallSize3) pg.circle(earringX, earringY + dropSpacing, smallSize1) pg.circle(earringX, earringY + dropSpacing * 1.8, smallSize2) pg.circle(earringX, earringY + dropSpacing * 2.5, smallSize3) } else if (m.ornament === "Amp") { pg.rectMode(CENTER) const markWidth = m.w * 0.03 const markHeight = m.h * 0.15 const markX = m.w * 0.38 const markY = 0 pg.rect(-markX, markY, markWidth, markHeight) pg.rect(markX, markY, markWidth, markHeight) } else if (m.ornament === "Crest") { const spikeCount = 5 const baseWidth = m.w * 0.1 const spacing = m.w * 0.15 const maskTopY = -m.h * 0.4 const heights = [ m.h * 0.16, m.h * 0.22, m.h * 0.26, m.h * 0.22, m.h * 0.16 ] const verticalOffsets = [50, 0, 0, 0, 50] pg.stroke(0, 0, 0) pg.strokeWeight(m.w * 0.015) for (let i = 0; i < spikeCount; i++) { const x = (i - (spikeCount - 1) / 2) * spacing const spikeHeight = heights[i] const baseY = maskTopY + verticalOffsets[i] const spikeY = baseY - spikeHeight const isOuter = (i === 0 || i === spikeCount - 1) const angleOffset = isOuter ? (i === 0 ? baseWidth * 0.3 : -baseWidth * 0.3) : 0 pg.triangle( x, spikeY, x - baseWidth / 2 + (i === 0 ? angleOffset : 0), baseY, x + baseWidth / 2 + (i === spikeCount - 1 ? angleOffset : 0), baseY ) const connectorHeight = m.h * 0.10 const topWidth = baseWidth * 0.9 const bottomWidth = baseWidth * 0.6 pg.beginShape() pg.vertex(x - baseWidth / 2 + (i === 0 ? angleOffset : 0), baseY) pg.vertex(x + baseWidth / 2 + (i === spikeCount - 1 ? angleOffset : 0), baseY) pg.vertex(x + bottomWidth / 2, baseY + connectorHeight) pg.vertex(x - bottomWidth / 2, baseY + connectorHeight) pg.endShape(CLOSE) } pg.noStroke() } else if (m.ornament === "Bestia") { pg.fill(0, 0, 10) const hornBaseY = -m.h * 0.25 const hornSpacing = m.w * 0.25 const hornHeight = m.h * 0.35 const hornWidth = m.w * 0.12 for (let side of [-1, 1]) { pg.push() pg.translate(hornSpacing * side, hornBaseY) pg.scale(side, 1) pg.rotate(-0.25) pg.beginShape() pg.vertex(hornWidth * 0.3, 0) pg.vertex(-hornWidth * 0.3, 0) pg.bezierVertex( -hornWidth * 0.5, -hornHeight * 0.15, -hornWidth * 0.7, -hornHeight * 0.25, -hornWidth * 0.6, -hornHeight * 0.35 ) pg.vertex(-hornWidth * 0.9, -hornHeight * 0.32) pg.vertex(-hornWidth * 0.55, -hornHeight * 0.45) pg.bezierVertex( -hornWidth * 0.65, -hornHeight * 0.55, -hornWidth * 0.6, -hornHeight * 0.65, -hornWidth * 0.45, -hornHeight * 0.72 ) pg.vertex(-hornWidth * 0.75, -hornHeight * 0.70) pg.vertex(-hornWidth * 0.35, -hornHeight * 0.82) pg.bezierVertex( -hornWidth * 0.3, -hornHeight * 0.92, -hornWidth * 0.1, -hornHeight * 0.98, hornWidth * 0.05, -hornHeight ) pg.bezierVertex( hornWidth * 0.15, -hornHeight * 0.75, hornWidth * 0.2, -hornHeight * 0.45, hornWidth * 0.3, 0 ) pg.endShape(CLOSE) pg.pop() } } else if (m.ornament === "Root") { const tuskWidth = m.w * 0.15 const tuskHeight = m.h * 0.4 const tuskSpacing = m.w * 0.20 const tuskY = m.h * 0.22 pg.push() pg.translate(-tuskSpacing, tuskY) pg.beginShape() pg.vertex(-tuskWidth * 0.35, 0) pg.bezierVertex( -tuskWidth * 0.25, tuskHeight * 0.6, -tuskWidth * 0.05, tuskHeight * 0.8, 0, tuskHeight ) pg.bezierVertex( tuskWidth * 0.35, tuskHeight * 0.8, tuskWidth * 0.5, tuskHeight * 0.6, tuskWidth * 0.05, 0 ) pg.endShape(CLOSE) pg.pop() pg.push() pg.translate(tuskSpacing, tuskY) pg.beginShape() pg.vertex(-tuskWidth * 0.35, 0) pg.bezierVertex( -tuskWidth * 0.25, tuskHeight * 0.6, -tuskWidth * 0.15, tuskHeight * 0.8, 0, tuskHeight ) pg.bezierVertex( tuskWidth * 0.15, tuskHeight * 0.8, tuskWidth * 0.25, tuskHeight * 0.6, tuskWidth * 0.35, 0 ) pg.endShape(CLOSE) pg.pop() } else if (m.ornament === "Gauge") { const gaugeSize = m.w * 0.12 const gaugeX = m.w * 0.42 const gaugeY = m.h * 0.12 pg.circle(-gaugeX, gaugeY, gaugeSize) pg.circle(gaugeX, gaugeY, gaugeSize) pg.push() pg.erase() const holeSize = gaugeSize * 0.5 pg.circle(-gaugeX, gaugeY, holeSize) pg.circle(gaugeX, gaugeY, holeSize) pg.noErase() pg.pop() } else if (m.ornament === "Thorns") { const spikeCount = 3 const spikeWidth = m.w * 0.05 const spikeHeight = m.h * 0.08 const earX = m.w * 0.42 const startY = m.h * 0.05 const spacing = m.h * 0.1 for (let side of [-1, 1]) { for (let i = 0; i < spikeCount; i++) { const x = earX * side const y = startY + i * spacing pg.push() pg.translate(x, y) pg.triangle( 0, -spikeHeight * 0.5, -spikeWidth * 0.5 * side, spikeHeight * 0.5, spikeWidth * 0.5 * side, spikeHeight * 0.5 ) pg.pop() } } } else if (m.ornament === "Tandem") { const earringSize = m.w * 0.06 const earringX = m.w * 0.44 const earringY1 = m.h * 0.10 const earringY2 = m.h * 0.20 pg.circle(-earringX, earringY1, earringSize) pg.circle(earringX, earringY1, earringSize) pg.circle(-earringX, earringY2, earringSize * 0.8) pg.circle(earringX, earringY2, earringSize * 0.8) } else if (m.ornament === "Spike") { const spikeWidth = m.w * 0.12 const spikeHeight = m.h * 0.22 const chinY = m.h * 0.32 pg.push() pg.translate(0, chinY) pg.triangle( -spikeWidth / 2, 0, spikeWidth / 2, 0, 0, spikeHeight ) pg.pop() } pg.pop() } const vertSrc = ` attribute vec3 aPosition; attribute vec2 aTexCoord; varying vec2 vTexCoord; void main() { vTexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y); vec4 positionVec4 = vec4(aPosition, 1.0); positionVec4.xy = positionVec4.xy * 2.0 - 1.0; gl_Position = positionVec4; } `; const fragDigitalStitchOptimized = ` #ifdef GL_ES precision mediump float; #endif varying vec2 vTexCoord; uniform float u_time; uniform vec2 u_resolution; uniform sampler2D u_texture; uniform float u_gridX; uniform bool u_forceMonochrome; uniform bool u_applyNoise; uniform float u_symbolOffset; uniform float u_vocabSize; uniform float u_symbolSize; uniform bool u_bwMode; float hash21(vec2 p){ return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); } // Simple 2D Perlin-style noise function float noise2D(vec2 p) { vec2 i = floor(p); vec2 f = fract(p); // Smooth interpolation f = f * f * (3.0 - 2.0 * f); // Four corners float a = hash21(i); float b = hash21(i + vec2(1.0, 0.0)); float c = hash21(i + vec2(0.0, 1.0)); float d = hash21(i + vec2(1.0, 1.0)); // Bilinear interpolation return mix(mix(a, b, f.x), mix(c, d, f.x), f.y); } // Convert RGB to HSB vec3 rgb2hsb(vec3 c) { vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); float d = q.x - min(q.w, q.y); float e = 1.0e-10; return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); } // Convert HSB to RGB vec3 hsb2rgb(vec3 c) { vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); } float getCharPattern(float shapeId, vec2 cellUV, float brightness){ vec2 p = (cellUV - 0.5) / u_symbolSize; int id = int(shapeId); if (id == 0) { // Horizontal bar return step(abs(p.y), 0.28); } if (id == 1) { // Vertical bar return step(abs(p.x), 0.28); } if (id == 2) { // Filled circle return step(length(p), 0.48); } if (id == 3) { // Square return step(max(abs(p.x), abs(p.y)), 0.45); } if (id == 4) { // Diamond return step(abs(p.x) + abs(p.y), 0.65); } if (id == 5) { // Thick cross return max(step(abs(p.y), 0.22), step(abs(p.x), 0.22)); } if (id == 6) { // Ring float ring = length(p); return step(ring, 0.48) * (1.0 - step(ring, 0.12)); } if (id == 7) { // Checkerboard return mod(floor(cellUV.x*2.0) + floor(cellUV.y*2.0), 2.0); } if (id == 8) { // Small circle return step(length(p), 0.38); } if (id == 9) { // X return step(abs(abs(p.x) - abs(p.y)), 0.18); } if (id == 10) { // Rounded quad vec2 corner = abs(p) - vec2(0.22); return step(length(corner), 0.22); } if (id == 11) { // Thin cross return max(step(abs(p.y), 0.18), step(abs(p.x), 0.18)); } if (id == 12) { // Heart float lobeL = step(length(p - vec2(-0.15, 0.13)), 0.20); float lobeR = step(length(p - vec2(0.15, 0.13)), 0.20); float tri = step(abs(p.x) - (p.y + 0.35) * 0.73, 0.0) * step(-0.35, p.y) * step(p.y, 0.13); return min(lobeL + lobeR + tri, 1.0); } if (id == 13) { // 5-petal flower float a = atan(p.y, p.x); float r = length(p); return step(r, abs(cos(a * 2.5)) * 0.15 + 0.25); } if (id == 14) { // Triangle up return step(abs(p.x) * 0.577 + p.y, 0.25) * step(-p.y, 0.35); } if (id == 15) { // Triangle down return step(abs(p.x) * 0.577 - p.y, 0.25) * step(p.y, 0.35); } if (id == 16) { // Arrow up float shaft = step(abs(p.x), 0.1) * step(p.y, 0.1) * step(-0.3, p.y); float head = step(abs(p.x) - (0.3 - p.y), 0.0) * step(0.1, p.y) * step(p.y, 0.3); return max(shaft, head); } if (id == 17) { // Arrow right float shaft = step(abs(p.y), 0.1) * step(p.x, 0.1) * step(-0.3, p.x); float head = step(abs(p.y) - (0.3 - p.x), 0.0) * step(0.1, p.x) * step(p.x, 0.3); return max(shaft, head); } if (id == 18) { // Hexagon vec2 q = abs(p); return step(q.x * 0.866 + q.y * 0.5, 0.4); } if (id == 19) { // Dot return step(length(p), 0.12); } if (id == 20) { // Two circles return max(step(length(p - vec2(-0.15, 0.0)), 0.15), step(length(p - vec2(0.15, 0.0)), 0.15)); } if (id == 21) { // Grid return max(step(0.7, fract(cellUV.x * 3.0)), step(0.7, fract(cellUV.y * 3.0))); } if (id == 22) { // Diagonal / return step(0.7, fract((cellUV.x + cellUV.y) * 5.0)); } if (id == 23) { // Diagonal \\ return step(0.7, fract((cellUV.x - cellUV.y) * 5.0)); } if (id == 24) { // Cross with dots float plus = max(step(abs(p.y), 0.12), step(abs(p.x), 0.12)); float dots = step(length(p - vec2(0.3, 0.3)), 0.08) + step(length(p - vec2(-0.3, 0.3)), 0.08) + step(length(p - vec2(0.3, -0.3)), 0.08) + step(length(p - vec2(-0.3, -0.3)), 0.08); return min(plus + dots, 1.0); } if (id == 25) { // Four corner dots return max(max(step(length(p - vec2(-0.2, -0.2)), 0.15), step(length(p - vec2(0.2, -0.2)), 0.15)), max(step(length(p - vec2(-0.2, 0.2)), 0.15), step(length(p - vec2(0.2, 0.2)), 0.15))); } if (id == 26) { // Quincunx float center = step(length(p), 0.15); float pts = step(length(p - vec2(0.0, 0.25)), 0.12) + step(length(p - vec2(0.25, 0.0)), 0.12) + step(length(p - vec2(0.0, -0.25)), 0.12) + step(length(p - vec2(-0.25, 0.0)), 0.12); return min(center + pts, 1.0); } if (id == 27) { // Octagon vec2 q = abs(p); return step(max(q.x * 0.707 + q.y * 0.707, max(q.x, q.y)), 0.4); } if (id == 28) { // Vertical stripes return step(0.6, fract(cellUV.x * 4.0)); } if (id == 29) { // Horizontal stripes return step(0.6, fract(cellUV.y * 4.0)); } if (id == 30) { // Concentric rings float r = length(p); return step(0.7, fract(r * 10.0)); } if (id == 31) { // Crescent float outer = step(length(p), 0.38); float inner = step(length(p - vec2(0.18, 0.0)), 0.32); return outer * (1.0 - inner); } if (id == 32) { // 5-pointed star float a = atan(p.y, p.x) + 1.5708; float r = length(p); return step(r, cos(floor(0.5 + a / 1.2566) * 1.2566 - a) * 0.45); } if (id == 33) { // Scouts [REPLACED] float a = atan(p.y, p.x); float r = length(p); float star = step(r, abs(cos(a * 4.0)) * 0.32 + 0.05); float diamond = step(abs(p.x) + abs(p.y), 0.10); return max(star, diamond); } if (id == 34) { // Bowtie [REPLACED] return step(abs(p.x) * 0.5 - abs(p.y), 0.0) * step(abs(p.x), 0.4) * step(abs(p.y), 0.35); } if (id == 35) { // Rook float body = step(abs(p.x), 0.22) * step(abs(p.y), 0.32); float notch1 = step(abs(p.x + 0.12), 0.04) * step(p.y, 0.35) * step(0.22, p.y); float notch2 = step(abs(p.x - 0.12), 0.04) * step(p.y, 0.35) * step(0.22, p.y); return body * (1.0 - notch1) * (1.0 - notch2); } if (id == 36) { // Circuit node [REPLACED] float c = step(length(p), 0.1); float l1 = step(abs(p.y), 0.03) * step(abs(p.x), 0.4); float l2 = step(abs(p.x), 0.03) * step(abs(p.y), 0.4); return min(c + l1 + l2, 1.0); } if (id == 37) { // Resistor [REPLACED] float l1 = step(abs(p.y), 0.03) * step(abs(p.x + 0.3), 0.1); float l2 = step(abs(p.y), 0.03) * step(abs(p.x - 0.3), 0.1); float box = step(abs(p.y), 0.1) * step(abs(p.x), 0.2); return min(l1 + l2 + box, 1.0); } if (id == 38) { // Trace L [REPLACED] float h = step(abs(p.y), 0.03) * step(p.x, 0.4) * step(-0.03, p.x); float v = step(abs(p.x), 0.03) * step(p.y, 0.03) * step(-0.4, p.y); return max(h, v); } if (id == 39) { // Lightning vec2 q = p * 2.5; float b1 = step(abs(q.x - 0.2), 0.18) * step(q.y, 0.8) * step(0.0, q.y); float b2 = step(abs(q.x + 0.1), 0.25) * step(q.y, 0.15) * step(-0.15, q.y); float b3 = step(abs(q.x + 0.2), 0.18) * step(q.y, -0.0) * step(-0.8, q.y); return min(b1 + b2 + b3, 1.0); } if (id == 40) { // Hourglass float w = min(abs(p.y) * 0.9 + 0.03, 0.28); return step(abs(p.x), w) * step(abs(p.y), 0.38); } if (id == 41) { // Infinity float l1 = length(p - vec2(-0.18, 0.0)); float l2 = length(p - vec2(0.18, 0.0)); return max(step(l1, 0.2) * (1.0 - step(l1, 0.08)), step(l2, 0.2) * (1.0 - step(l2, 0.08))); } if (id == 42) { // Wave crest [REPLACED] return step(abs(p.y - sin(p.x * 8.0) * 0.1), 0.06) * step(abs(p.x), 0.4); } if (id == 43) { // Eye float almond = step(abs(p.x) * 0.5 + abs(p.y), 0.22); return max(almond * 0.7, step(length(p), 0.08)); } if (id == 44) { // Skull float head = step(length(p - vec2(0.0, 0.08)), 0.26); float jaw = step(abs(p.x), 0.14) * step(abs(p.y + 0.2), 0.1); float eyeL = 1.0 - step(length(p - vec2(-0.09, 0.12)), 0.07); float eyeR = 1.0 - step(length(p - vec2(0.09, 0.12)), 0.07); return min(head + jaw, 1.0) * eyeL * eyeR; } if (id == 45) { // Spade float lobeL = step(length(p - vec2(-0.15, -0.05)), 0.20); float lobeR = step(length(p - vec2(0.15, -0.05)), 0.20); float tri = step(abs(p.x) - (0.32 - p.y) * 0.95, 0.0) * step(-0.05, p.y) * step(p.y, 0.32); float stem = step(abs(p.x), 0.07) * step(p.y, -0.22) * step(-0.34, p.y); return min(lobeL + lobeR + tri + stem, 1.0); } if (id == 46) { // Club float c1 = step(length(p - vec2(0.0, 0.18)), 0.16); float c2 = step(length(p - vec2(-0.16, -0.05)), 0.16); float c3 = step(length(p - vec2(0.16, -0.05)), 0.16); float center = step(length(p - vec2(0.0, 0.03)), 0.10); float stem = step(abs(p.x), 0.07) * step(p.y, -0.05) * step(-0.34, p.y); return min(c1 + c2 + c3 + center + stem, 1.0); } if (id == 47) { // Trefoil float c1 = step(length(p - vec2(0.0, 0.15)), 0.14); float c2 = step(length(p - vec2(-0.13, -0.05)), 0.14); float c3 = step(length(p - vec2(0.13, -0.05)), 0.14); return min(c1 + c2 + c3, 1.0); } if (id == 48) { // Peace sign float r = length(p); float ring = step(r, 0.35) * (1.0 - step(r, 0.27)); float inside = step(r, 0.30); float vert = step(abs(p.x), 0.04) * inside; float legL = step(abs(p.x + p.y * 0.65), 0.04) * step(p.y, 0.0) * inside; float legR = step(abs(p.x - p.y * 0.65), 0.04) * step(p.y, 0.0) * inside; return min(ring + vert + legL + legR, 1.0); } if (id == 49) { // Warriors [REPLACED] float armH = step(abs(p.y), max(0.0, 0.12 - abs(p.x) * 0.32)) * step(abs(p.x), 0.38); float armV = step(abs(p.x), max(0.0, 0.12 - abs(p.y) * 0.32)) * step(abs(p.y), 0.38); float diamond = step(abs(p.x) + abs(p.y), 0.13); return max(max(armH, armV), diamond); } if (id == 50) { // Nobles [REPLACED] float d1 = step(abs(p.x) + abs(p.y), 0.12); float d2 = step(abs(p.x) + abs(p.y - 0.26), 0.10); float d3 = step(abs(p.x) + abs(p.y + 0.26), 0.10); float d4 = step(abs(p.x - 0.26) + abs(p.y), 0.10); float d5 = step(abs(p.x + 0.26) + abs(p.y), 0.10); return min(d1 + d2 + d3 + d4 + d5, 1.0); } if (id == 51) { // Conflux [REPLACED] float c = 0.866; float s = 0.5; vec2 q1 = vec2((p.x - 0.10) * c + (p.y - 0.08) * s, -(p.x - 0.10) * s + (p.y - 0.08) * c); vec2 q2 = vec2((p.x + 0.10) * c + (p.y + 0.08) * s, -(p.x + 0.10) * s + (p.y + 0.08) * c); float r1 = step(max(abs(q1.x), abs(q1.y)), 0.14); float r2 = step(max(abs(q2.x), abs(q2.y)), 0.14); return min(r1 + r2, 1.0); } return step(max(abs(p.x), abs(p.y)), 0.2); // fallback } void main(){ vec2 uv = vTexCoord; float GRID_X = max(20.0, u_gridX); float aspect = u_resolution.x / u_resolution.y; vec2 gridCount = vec2(GRID_X, GRID_X / aspect); vec2 gridUV = uv * gridCount; vec2 cellID = floor(gridUV); vec2 cellUV = fract(gridUV); vec2 cellCenter = (cellID + 0.5) / gridCount; vec4 cellColor = texture2D(u_texture, cellCenter); if (cellColor.a < 0.01) { gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); return; } // Enhanced brightness calculation with better contrast float cellBri = dot(cellColor.rgb, vec3(0.299, 0.587, 0.114)); cellBri = pow(cellBri, 0.8); // Gamma adjustment for better distribution // Conditionally apply Perlin noise texture // Slow-moving organic texture across the surface if (u_applyNoise) { vec2 noiseCoord = cellCenter * u_resolution * 0.003 + u_time * 0.05; float noiseVal = noise2D(noiseCoord); // Apply subtle noise variation to brightness (affects pattern selection) cellBri = cellBri + (noiseVal - 0.5) * 0.12; } cellBri = clamp(cellBri, 0.0, 1.0); // Symbol selection — brightness picks an index within the active vocabulary, // which maps to a contiguous block of slots starting at u_symbolOffset. // u_vocabSize controls how many distinct symbols a piece uses (1, 2, 5, 10, or 52). float TYPES = 52.0; float vocab = max(u_vocabSize, 1.0); float idx = floor(cellBri * vocab); idx = min(idx, vocab - 1.0); // clamp top edge (cellBri = 1.0 case) float shapeId = mod(u_symbolOffset + idx, TYPES); // Get the pattern mask float mask = getCharPattern(shapeId, cellUV, cellBri); mask = clamp(mask, 0.0, 1.0); // Convert cell color to HSB vec3 hsbColor = rgb2hsb(cellColor.rgb); // Check if this is a grayscale/desaturated color (like the form) float isGrayscale = step(hsbColor.y, 0.15); // Saturation threshold — lower = more cells use chromatic path // OVERRIDE: Force monochrome mode if requested if (u_forceMonochrome) { isGrayscale = 1.0; } vec3 bgColor, symbolColor; if (isGrayscale > 0.5 || u_forceMonochrome) { // MONOCHROMATIC MODE - use single hue with varying sat/brightness float baseHue = hsbColor.x; if (u_forceMonochrome) { // For monotone palettes: create monochromatic scheme bgColor = hsb2rgb(vec3(baseHue, hsbColor.y * 0.3, hsbColor.z * 1.2)); symbolColor = hsb2rgb(vec3(baseHue, hsbColor.y * 0.9, hsbColor.z * 0.7)); } else { // For form/grayscale elements: true grayscale bgColor = vec3(hsbColor.z * 1.15); symbolColor = vec3(hsbColor.z * 0.6); } } else { // COMPLEMENTARY COLOR MODE (for vibrant mask fills) // Create background color - slightly adjusted version of original bgColor = hsb2rgb(vec3(hsbColor.x, hsbColor.y * 0.8, hsbColor.z * 1.2)); // Create symbol color - complementary hue float symbolHue = mod(hsbColor.x + 0.5, 1.0); // Vary symbol color based on cell position for more variety float cellHash = hash21(cellID); float hueVariation = (cellHash - 0.5) * 0.2; symbolHue = mod(symbolHue + hueVariation, 1.0); // Choose saturation and brightness for symbol float symbolSat = mix(0.7, 1.0, cellHash); float symbolBri = cellBri > 0.5 ? 0.3 : 0.9; symbolColor = hsb2rgb(vec3(symbolHue, symbolSat, symbolBri)); } // Mix background and symbol colors vec3 finalColor = mix(bgColor, symbolColor, mask); // Ink mode — pure black & white, hard luminance threshold (Etched palette). if (u_bwMode) { float lum = dot(finalColor, vec3(0.299, 0.587, 0.114)); finalColor = lum > 0.5 ? vec3(1.0) : vec3(0.0); } gl_FragColor = vec4(finalColor, cellColor.a); } ` function logTraits() { if (!DEBUG) return console.log('%c╔═══════════════════════════════════════════════════════════╗', 'color: #FF00FF;') console.log('%c║ SATARI TRAITS ║', 'color: #FF00FF; font-weight: bold; font-size: 16px;') console.log('%c╚═══════════════════════════════════════════════════════════╝', 'color: #FF00FF;') console.log(`%c SEED: ${CURRENT_SEED}`, 'color: #FFD700; font-weight: bold; font-size: 14px;') console.log('') console.log('%c ─── PRIMARY ───', 'color: #00FFFF; font-weight: bold;') console.log(`%c Form: %c${TRAITS.displayedArchetype}`, 'color: #888;', 'color: #FFF; font-weight: bold;') console.log(`%c House: %c${TRAITS.house}`, 'color: #888;', 'color: #FFF; font-weight: bold;') console.log(`%c Class: %c${TRAITS.role}`, 'color: #888;', 'color: #FFF; font-weight: bold;') console.log(`%c Palette: %c${TRAITS.paletteName}${TRAITS._basePalette ? ' (over ' + TRAITS._basePalette + ')' : ''}`, 'color: #888;', 'color: #FFF; font-weight: bold;') console.log(`%c Realm: %c${TRAITS.realm}`, 'color: #888;', 'color: #FFF; font-weight: bold;') console.log(`%c Aura: %c${TRAITS.aura}`, 'color: #888;', 'color: #FFF; font-weight: bold;') console.log('') console.log('%c ─── IDENTITY ───', 'color: #00FFFF; font-weight: bold;') console.log(`%c Doctrine: %c${TRAITS.doctrine}`, 'color: #888;', 'color: #FFF;') console.log(`%c Spacecraft: %c${TRAITS.spacecraft}`, 'color: #888;', 'color: #FFF;') console.log('') console.log('%c ─── FACE ───', 'color: #00FFFF; font-weight: bold;') console.log(`%c Sight: %c${TRAITS.sight}`, 'color: #888;', 'color: #FFF;') console.log(`%c Iris: %c${TRAITS.iris}`, 'color: #888;', 'color: #FFF;') console.log(`%c Voice: %c${TRAITS.voice}`, 'color: #888;', 'color: #FFF;') console.log(`%c Scent: %c${TRAITS.scent}`, 'color: #888;', 'color: #FFF;') console.log(`%c Hollows: %c${TRAITS.hollows}`, 'color: #888;', 'color: #FFF;') console.log(`%c Ornament: %c${TRAITS.ornament}`, 'color: #888;', 'color: #FFF;') console.log('') console.log('%c ─── ANIMATION ───', 'color: #00FFFF; font-weight: bold;') console.log(`%c Fill: %c${TRAITS.fillVariant}`, 'color: #888;', 'color: #FFF;') console.log(`%c Blend: %c${TRAITS.blendSchema}`, 'color: #888;', 'color: #FFF;') console.log(`%c Origin: %c${TRAITS.originTopology}`, 'color: #888;', 'color: #FFF;') console.log(`%c Spawn: %c${TRAITS.spawnRhythm}`, 'color: #888;', 'color: #FFF;') console.log('') console.log('%c ─── CONTROLS ───', 'color: #888;') console.log('%c N = Restart | S = Save PNG | Space = Freeze | Esc = Reset Modes', 'color: #666; font-size: 11px;') console.log('%c═══════════════════════════════════════════════════════════════', 'color: #FF00FF;') } function resetAndRegenerate() { fillAnimations = [] orbitingElements = [] masks = [] maskBoundsCache = [] globalBounds = null eyesFullyOn = false regenStartFrame = frameCount // Track when this regeneration started nextSpawnFrame = 0 _breathStartMillis = null if (animationPool) { animationPool.clear() } if (fillPersistentLayer) { fillPersistentLayer.clear() } applySeed() TRAITS = buildTraits() bwMode = TRAITS.paletteName === "Etched" PARAMS = resolveParams(TRAITS) logTraits() layoutMasks() calculateMaskBounds() isDirty = true drawStaticLayers() initTopology() initOrbitingElements() } // Exposed for external tools (e.g. the rater): swap to a new seed without // reloading the page. Keeps the same shader/canvas/buffers — only re-rolls // traits and rebuilds layout. Much faster than an iframe reload. window.regenerateWithSeed = function (newSeed) { CURRENT_SEED = newSeed >>> 0 resetAndRegenerate() } function getTierForWidth(displayWidth) { let tier = QUALITY_TIERS[0] for (const t of QUALITY_TIERS) { if (displayWidth >= t.minWidth) tier = t } return tier } function getDisplayWidth() { const canvas = document.querySelector('canvas') if (canvas) return canvas.getBoundingClientRect().width return window.innerWidth } function resizeAllBuffers(w, h) { // The render canvas is off-DOM (the DOM holds the square display canvas), // so reach it via the shim global rather than querySelector. const mainCanvas = _mainCanvas if (mainCanvas) { mainCanvas.width = w mainCanvas.height = h width = w height = h _designScale = w / 750 if (_mainPG) { _mainPG.width = w _mainPG.height = h _mainPG.canvas = mainCanvas _mainPG.drawingContext = mainCanvas.getContext('2d') _mainPG.drawingContext.imageSmoothingEnabled = false window.drawingContext = _mainPG.drawingContext } } if (_displayCanvas) { _displayCanvas.width = w _displayCanvas.height = w // Resizing resets 2d context state — restore nearest-neighbor blits. _displayCtx.imageSmoothingEnabled = false } staticLayerCache = createGraphics(w, h) staticLayerCache.pixelDensity(1) staticLayerCache.colorMode(HSB, 360, 100, 100, 100) formPart1Cache = createGraphics(w, h) formPart1Cache.pixelDensity(1) formPart1Cache.colorMode(HSB, 360, 100, 100, 100) formPart2Cache = createGraphics(w, h) formPart2Cache.pixelDensity(1) formPart2Cache.colorMode(HSB, 360, 100, 100, 100) maskSilhouetteCache = createGraphics(w, h) maskSilhouetteCache.pixelDensity(1) fillBuffer = createGraphics(w, h) fillBuffer.pixelDensity(1) fillBuffer.colorMode(HSB, 360, 100, 100, 100) fillPersistentLayer = createGraphics(w, h) fillPersistentLayer.pixelDensity(1) fillPersistentLayer.colorMode(HSB, 360, 100, 100, 100) eyesCache = createGraphics(w, h) eyesCache.pixelDensity(1) eyesCache.colorMode(HSB, 360, 100, 100, 100) eyesBlockingCache = createGraphics(w, h) eyesBlockingCache.pixelDensity(1) eyesBlockingCache.colorMode(HSB, 360, 100, 100, 100) omniaEyesBase = createGraphics(w, h) omniaEyesBase.pixelDensity(1) omniaEyesBase.colorMode(HSB, 360, 100, 100, 100) orbitBuffer = createGraphics(w, h) orbitBuffer.pixelDensity(1) orbitBuffer.colorMode(HSB, 360, 100, 100, 100) meltBuffer = createGraphics(w, h) meltBuffer.pixelDensity(1) meltBuffer.colorMode(HSB, 360, 100, 100, 100) corruptBuffer = createGraphics(w, h) corruptBuffer.pixelDensity(1) corruptBuffer.colorMode(HSB, 360, 100, 100, 100) clipBuffer = createGraphics(w, h) clipBuffer.pixelDensity(1) clipBuffer.colorMode(HSB, 360, 100, 100, 100) finalComposite = createGraphics(w, h) finalComposite.pixelDensity(1) finalComposite.colorMode(HSB, 360, 100, 100, 100) finalShadedBuffer = createGraphics(w, h, WEBGL) finalShadedBuffer.pixelDensity(1) finalShadedBuffer.noStroke() finalShadedBuffer.rectMode(CENTER) asciiShader = finalShadedBuffer.createShader(vertSrc, fragDigitalStitchOptimized) } function applyTier(tier) { const prevTier = _currentTier _currentTier = tier _tierMaxAnims = tier.maxAnims _tierGridDensity = tier.gridCols _tierNoiseOverride = tier.noise ? null : false frameRate(tier.fps) if (!prevTier || prevTier.canvasW !== tier.canvasW) { const newW = tier.canvasW const newH = floor(newW * ASPECT_RATIO) if (width !== newW && width > 0) { resizeAllBuffers(newW, newH) resetAndRegenerate() } } } function initTierObserver() { // Capture is a one-shot static render. Skip the tier/visibility observers: // the visibility observer in particular flips _running back on and restarts // the draw loop when the canvas is on-screen, which would undo the capture // freeze and resume animation (trail/persist-buffer shimmer, etc.). if (typeof window.$art !== 'undefined' && window.$art.captureMode) return if (typeof ResizeObserver === 'undefined') return const canvas = document.querySelector('canvas') if (!canvas) return let _resizeTimeout = null const observer = new ResizeObserver(() => { clearTimeout(_resizeTimeout) _resizeTimeout = setTimeout(() => { const displayW = canvas.getBoundingClientRect().width const tier = getTierForWidth(displayW) if (!_currentTier || tier.canvasW !== _currentTier.canvasW) { _pendingTier = tier // Defer — applied at start of next draw() } }, 150) }) observer.observe(canvas) if (typeof IntersectionObserver !== 'undefined') { const visObserver = new IntersectionObserver((entries) => { _running = entries[0].isIntersecting if (_running) requestAnimationFrame(_loop) }, { threshold: 0.05 }) visObserver.observe(canvas) } } function setup() { readSeed() applySeed() const initialTier = getTierForWidth(getDisplayWidth()) _currentTier = initialTier _tierMaxAnims = initialTier.maxAnims _tierGridDensity = initialTier.gridCols _tierNoiseOverride = initialTier.noise ? null : false const canvasW = initialTier.canvasW let canvas = createCanvas(canvasW, floor(canvasW * ASPECT_RATIO)) pixelDensity(1) frameRate(initialTier.fps) colorMode(HSB, 360, 100, 100, 100) drawingContext.imageSmoothingEnabled = false _designScale = width / 750 animationPool = new AnimationPool() TRAITS = buildTraits() bwMode = TRAITS.paletteName === "Etched" PARAMS = resolveParams(TRAITS) staticLayerCache = createGraphics(width, height) staticLayerCache.pixelDensity(1) staticLayerCache.colorMode(HSB, 360, 100, 100, 100) formPart1Cache = createGraphics(width, height) formPart1Cache.pixelDensity(1) formPart1Cache.colorMode(HSB, 360, 100, 100, 100) formPart2Cache = createGraphics(width, height) formPart2Cache.pixelDensity(1) formPart2Cache.colorMode(HSB, 360, 100, 100, 100) maskSilhouetteCache = createGraphics(width, height) maskSilhouetteCache.pixelDensity(1) fillBuffer = createGraphics(width, height) fillBuffer.pixelDensity(1) fillBuffer.colorMode(HSB, 360, 100, 100, 100) fillPersistentLayer = createGraphics(width, height) fillPersistentLayer.pixelDensity(1) fillPersistentLayer.colorMode(HSB, 360, 100, 100, 100) eyesCache = createGraphics(width, height) eyesCache.pixelDensity(1) eyesCache.colorMode(HSB, 360, 100, 100, 100) eyesBlockingCache = createGraphics(width, height) eyesBlockingCache.pixelDensity(1) eyesBlockingCache.colorMode(HSB, 360, 100, 100, 100) omniaEyesBase = createGraphics(width, height) omniaEyesBase.pixelDensity(1) omniaEyesBase.colorMode(HSB, 360, 100, 100, 100) orbitBuffer = createGraphics(width, height) orbitBuffer.pixelDensity(1) orbitBuffer.colorMode(HSB, 360, 100, 100, 100) meltBuffer = createGraphics(width, height) meltBuffer.pixelDensity(1) meltBuffer.colorMode(HSB, 360, 100, 100, 100) corruptBuffer = createGraphics(width, height) corruptBuffer.pixelDensity(1) corruptBuffer.colorMode(HSB, 360, 100, 100, 100) clipBuffer = createGraphics(width, height) clipBuffer.pixelDensity(1) clipBuffer.colorMode(HSB, 360, 100, 100, 100) finalComposite = createGraphics(width, height) finalComposite.pixelDensity(1) finalComposite.colorMode(HSB, 360, 100, 100, 100) finalShadedBuffer = createGraphics(width, height, WEBGL) finalShadedBuffer.pixelDensity(1) finalShadedBuffer.noStroke() finalShadedBuffer.rectMode(CENTER) asciiShader = finalShadedBuffer.createShader(vertSrc, fragDigitalStitchOptimized) layoutMasks() calculateMaskBounds() drawStaticLayers() initTopology() initOrbitingElements() logTraits() initTierObserver() } function getBackgroundColor() { const bgType = PARAMS.background if (bgType === "Halo" || bgType === "Void") { return color(0, 0, 75) } else if (bgType === "Aero") { return color(200, 15, 85) } else if (bgType === "Rose") { return color(330, 25, 90) } else if (bgType === "Mint") { return color(150, 20, 88) } else if (bgType === "Mist") { return color(270, 18, 88) } else if (bgType === "Rise") { return color(20, 30, 90) } else if (bgType === "Fallen") { return color(0, 100, 90) } else { return color(PARAMS.palette[0]) } } function drawStaticLayers() { if (!isDirty) return staticLayerCache.clear() drawBackground(staticLayerCache, PARAMS.background) if (isTwoPartArchetype(TRAITS.archetype)) { formPart2Cache.clear() formPart2Cache.background(0, 0, 0, 0) drawArchetypePart2(formPart2Cache, TRAITS.count, TRAITS.archetype) formPart1Cache.clear() formPart1Cache.background(0, 0, 0, 0) drawArchetypePart1(formPart1Cache, TRAITS.count, TRAITS.archetype) } else { formPart2Cache.clear() formPart2Cache.background(0, 0, 0, 0) drawArchetype(formPart2Cache, TRAITS.count, TRAITS.archetype) formPart1Cache.clear() formPart1Cache.background(0, 0, 0, 0) } eyesCache.clear() eyesCache.background(0, 0, 0, 0) for (const m of masks) { drawMaskEyes(eyesCache, m) } if (TRAITS.iris === "Omnia") { omniaEyesBase.clear() omniaEyesBase.background(0, 0, 0, 0) for (const m of masks) { drawMaskEyesOmniaBase(omniaEyesBase, m) } } eyesBlockingCache.clear() eyesBlockingCache.background(0, 0, 0, 0) for (const m of masks) { drawMaskEyesBlocking(eyesBlockingCache, m) } maskSilhouetteCache.clear() maskSilhouetteCache.noStroke() maskSilhouetteCache.fill(255) for (const m of masks) drawMaskSilhouette(maskSilhouetteCache, m) isDirty = false } function stableRemove(arr, index) { arr.splice(index, 1) } function draw() { if (_pendingTier) { applyTier(_pendingTier) _pendingTier = null } fillPersistentLayer.drawingContext.globalCompositeOperation = 'source-over' fillPersistentLayer.drawingContext.globalAlpha = 1.0 clipBuffer.drawingContext.globalCompositeOperation = 'source-over' clipBuffer.drawingContext.globalAlpha = 1.0 meltBuffer.drawingContext.globalCompositeOperation = 'source-over' meltBuffer.drawingContext.globalAlpha = 1.0 corruptBuffer.drawingContext.globalCompositeOperation = 'source-over' corruptBuffer.drawingContext.globalAlpha = 1.0 fillBuffer.drawingContext.globalCompositeOperation = 'source-over' fillBuffer.drawingContext.globalAlpha = 1.0 finalComposite.drawingContext.globalCompositeOperation = 'source-over' finalComposite.drawingContext.globalAlpha = 1.0 orbitBuffer.drawingContext.globalCompositeOperation = 'source-over' orbitBuffer.drawingContext.globalAlpha = 1.0 if (!freezeMode) { for (let i = fillAnimations.length - 1; i >= 0; i--) { fillAnimations[i].update() if (fillAnimations[i].isDone()) { animationPool.release(fillAnimations[i]) stableRemove(fillAnimations, i) } } for (let orb of orbitingElements) { orb.update() } if (PARAMS.aura === "Radiant") { starburstRotation += 0.0025 } updateSkyfall() updateMelt() updateCorrupt() updateVent() } if (!freezeMode) { _cachedPart2Offset = formBreathOffsetPart2() _cachedPart1Offset = formBreathOffsetPart1() _cachedMaskOffset = maskBreathOffset() } const part2Offset = _cachedPart2Offset const part1Offset = _cachedPart1Offset const maskOffset = _cachedMaskOffset fillPersistentLayer.clear() fillPersistentLayer.background(0, 0, 0, 0) for (let s of fillAnimations) { fillBuffer.clear() s.display(fillBuffer) fillPersistentLayer.image(fillBuffer, 0, 0) } if (!freezeMode) spawner() if (PARAMS.aura !== "CorruptMask") { const clipCtx = clipBuffer.drawingContext clipBuffer.clear() clipCtx.save() clipCtx.translate(0, maskOffset) clipCtx.drawImage(maskSilhouetteCache.canvas, 0, 0) clipCtx.restore() fillPersistentLayer.push() fillPersistentLayer.drawingContext.save() fillPersistentLayer.drawingContext.globalCompositeOperation = 'destination-in' fillPersistentLayer.drawingContext.drawImage(clipBuffer.canvas, 0, 0) fillPersistentLayer.drawingContext.restore() fillPersistentLayer.pop() } orbitBuffer.clear() orbitBuffer.background(0, 0, 0, 0) if (PARAMS.aura === "Radiant") { drawStarburst(orbitBuffer) } if (PARAMS.aura === "Skyfall") { drawSkyfall(orbitBuffer) } if (PARAMS.aura === "Vent") { drawVent(orbitBuffer) } if (PARAMS.aura === "Kintsugi") { drawCrack(orbitBuffer) } for (let orb of orbitingElements) { orb.display(orbitBuffer, true) } if (!freezeMode) { _cachedEyeOpacity = getEyeOpacity() if (TRAITS.iris === "Omnia") _cachedOmniaCol = getOmniaColor() } finalComposite.clear() finalComposite.background(getBackgroundColor()) if (PARAMS.aura === "CorruptRealm") { corruptBuffer.clear() corruptBuffer.background(0, 0, 0, 0) corruptBuffer.image(staticLayerCache, 0, 0) for (let slice of corruptSlices) { if (slice.active) { corruptBuffer.noStroke() corruptBuffer.fill(0, 0, 0, 0) corruptBuffer.blendMode(REPLACE) corruptBuffer.rect(0, slice.y, width, slice.sliceHeight) corruptBuffer.blendMode(BLEND) let sliceImg = staticLayerCache.get(0, slice.y, width, slice.sliceHeight) corruptBuffer.image(sliceImg, slice.offset, slice.y) } } finalComposite.image(corruptBuffer, 0, 0) } else { finalComposite.image(staticLayerCache, 0, 0) } finalComposite.image(orbitBuffer, 0, 0) finalComposite.push() finalComposite.translate(0, part2Offset) finalComposite.image(formPart2Cache, 0, 0) finalComposite.pop() finalComposite.push() finalComposite.translate(0, part1Offset) finalComposite.image(formPart1Cache, 0, 0) finalComposite.pop() if (PARAMS.aura === "Melt") { meltBuffer.clear() meltBuffer.background(0, 0, 0, 0) drawMelt(meltBuffer) meltBuffer.push() meltBuffer.drawingContext.save() meltBuffer.drawingContext.globalCompositeOperation = 'destination-out' meltBuffer.push() meltBuffer.translate(0, maskOffset) meltBuffer.image(eyesBlockingCache, 0, 0) meltBuffer.pop() meltBuffer.drawingContext.restore() meltBuffer.pop() finalComposite.image(meltBuffer, 0, 0) } if (PARAMS.aura === "CorruptMask") { meltBuffer.clear() meltBuffer.background(0, 0, 0, 0) meltBuffer.image(fillPersistentLayer, 0, 0) meltBuffer.push() meltBuffer.drawingContext.save() meltBuffer.drawingContext.globalCompositeOperation = 'destination-in' meltBuffer.push() meltBuffer.translate(0, maskOffset) meltBuffer.image(maskSilhouetteCache, 0, 0) meltBuffer.pop() meltBuffer.drawingContext.restore() meltBuffer.pop() corruptBuffer.clear() corruptBuffer.background(0, 0, 0, 0) corruptBuffer.image(meltBuffer, 0, 0) corruptBuffer.push() corruptBuffer.translate(0, maskOffset) corruptBuffer.image(eyesBlockingCache, 0, 0) corruptBuffer.pop() const eyeOpacity = _cachedEyeOpacity if (eyeOpacity > 0) { corruptBuffer.push() corruptBuffer.translate(0, maskOffset) if (TRAITS.iris === "Omnia") { const omniaCol = _cachedOmniaCol || getOmniaColor() corruptBuffer.tint(red(omniaCol), green(omniaCol), blue(omniaCol), eyeOpacity * 255) corruptBuffer.image(omniaEyesBase, 0, 0) } else { corruptBuffer.tint(255, eyeOpacity * 255) corruptBuffer.image(eyesCache, 0, 0) } corruptBuffer.pop() corruptBuffer.noTint() } for (let slice of corruptSlices) { if (slice.active) { corruptBuffer.noStroke() corruptBuffer.fill(0, 0, 0, 0) corruptBuffer.blendMode(REPLACE) corruptBuffer.rect(slice.sliceX, slice.y, slice.sliceWidth, slice.sliceHeight) corruptBuffer.blendMode(BLEND) let sliceImg = fillPersistentLayer.get(slice.sliceX, slice.y, slice.sliceWidth, slice.sliceHeight) corruptBuffer.image(sliceImg, slice.sliceX + slice.offset, slice.y) } } finalComposite.image(corruptBuffer, 0, 0) } else { finalCompo