Name: Talking Blocks

Artist: REMO x DCsan

Description: Talking Blocks listens to the Blockchain hash # and creates a unique artwork with a signature stamped into the image that is a direct message from the blockchain. This provides the collector an assurance of authenticity while leveraging the blockchain to generate a unique message, a retina print of the blockchain hash #. This is an instantly recognizable visual signature. You can interact with the artwork to modulate a sonic reaction of oscillating circular waves. The permanent immutability of the underlying token hash # is combined with a non-repeatable signature from a person interacting with the artwork, all in real-time. In other words, you can have a conversation with the Blockchain.

https://linktr.ee/remocamero


Script JSON: {"type":"p5js","version":"1","aspectRatio":"1","animationLengthInSeconds":"0","interactive":"true","instructions":" Click image | Mint token"}

Script Type: p5js

Version: 1

Script Ratio: 1

Instructions: Click image | Mint token

Hashes Generated per Token: true

Dynamic Asset? true


Artist Ethereum Address: 0x5adb8988c310f3846ef1ac30ad1c35188cc77b31

Additional Payee: 0xd9f7fa14da177ff68bad47ab30fe933db75c3e43

Additional Payee Percentage: 80

Price: 0.1

Currency: ETH

Currency Address: N/A

Invocations: 512

Maximum Invocations: 512

License: NIFTY license

Token Ids: 55000000,55000001,55000002,55000003,55000004,55000005,55000006,55000007,55000008,55000009,55000010,55000011,55000012,55000013,55000014,55000015,55000016,55000017,55000018,55000019,55000020,55000021,55000022,55000023,55000024,55000025,55000026,55000027,55000028,55000029,55000030,55000031,55000032,55000033,55000034,55000035,55000036,55000037,55000038,55000039,55000040,55000041,55000042,55000043,55000044,55000045,55000046,55000047,55000048,55000049,55000050,55000051,55000052,55000053,55000054,55000055,55000056,55000057,55000058,55000059,55000060,55000061,55000062,55000063,55000064,55000065,55000066,55000067,55000068,55000069,55000070,55000071,55000072,55000073,55000074,55000075,55000076,55000077,55000078,55000079,55000080,55000081,55000082,55000083,55000084,55000085,55000086,55000087,55000088,55000089,55000090,55000091,55000092,55000093,55000094,55000095,55000096,55000097,55000098,55000099

Active? true

Paused? false


Script:

let audioReady = !1;
const maybeLog = (t, e) => {
          cfg.tick % 4 == 0 && console.log(t, e)
     },
     AudioInput = {
          createAudioMeter(t, e, i, a) {
               var s = t.createScriptProcessor(512);
               return s.onaudioprocess = AudioInput.volumeAudioProcess, s.clipping = !1, s.lastClip = 0, s.volume = 0, s.clipLevel = e || .98, s.averaging = i || .95, s.clipLag = a || 750, s.connect(t.destination), s.checkClipping = function() {
                    return !!this.clipping && (this.lastClip + this.clipLag < window.performance.now() && (this.clipping = !1), this.clipping)
               }, s.shutdown = function() {
                    this.disconnect(), this.onaudioprocess = null
               }, s
          },
          volumeAudioProcess(t) {
               for (var e, i = t.inputBuffer.getChannelData(0), a = i.length, s = 0, r = 0; r < a; r++) e = i[r], Math.abs(e) >= this.clipLevel && (this.clipping = !0, this.lastClip = window.performance.now()), s += e * e;
               t = Math.sqrt(s / a), t = Math.max(t, this.volume * this.averaging);
               cfg.volume = t
          },
          gotStream(t) {
               const e = new AudioContext,
                    i = e.createMediaStreamSource(t);
               t = AudioInput.createAudioMeter(e);
               i.connect(t), clog("gotStream")
          },
          initAudio() {
               try {
                    if (!navigator.permissions) return clog("no permissions object"), AudioInput.promptAudio();
                    navigator.permissions.query({
                         name: "microphone"
                    }).then(function(t) {
                         clog("audio permissions: ", t.state), "granted" == t.state ? (clog("granted"), AudioInput.promptAudio()) : "prompt" == t.state ? AudioInput.promptAudio() : "denied" == t.state && console.warn("audio is denied"), t.onchange = function() {
                              clog("audio.onChange")
                         }
                    })
               } catch (t) {
                    console.error("failed to initAudio", t)
               }
          },
          promptAudio() {
               clog("prompting..."), navigator.mediaDevices.getUserMedia({
                    audio: !0,
                    video: !1
               }).then(AudioInput.gotStream)
          }
     };
let glitchStarted = !1;
class Glitch {
     constructor(t, e = 0) {
          this.buffer = t, this.remainTicks = e, this.width = cfg.canvaSize, this.height = .05 * cfg.canvaSize, this.paused = !1, this.randomLine()
     }
     pause(t) {
          this.paused = t
     }
     start(t = 10) {
          this.remainTicks = t, clog("start glitch", cfg.tick)
     }
     setLine(t = 0) {
          this.gy = t - this.height / 2
     }
     randomLine() {
          this.gy = int(random(cfg.canvaSize - 2 * this.height), this.height)
     }
     check() {
          if (!this.paused) {
               if (this.remainTicks--, this.remainTicks < 0) return cfg.tick < 100 ? void 0 : void(100 * random() < cfg.glitchPct && (this.randomLine(), this.start()));
               this.gy += random(-cfg.vSpace, cfg.vSpace), this.render()
          }
     }
     writeColor(t, e, i, a, s, r) {
          e = 4 * (t + e * this.buffer.width);
          this.buffer.pixels[e] = i, this.buffer.pixels[1 + e] = a, this.buffer.pixels[2 + e] = s, this.buffer.pixels[3 + e] = r
     }
     render() {
          this.buffer.blendMode(BLEND), this.buffer.strokeWeight(0);
          for (let e = this.gy; e < this.gy + this.height; e += cfg.vSpace)
               for (let t = 0; t < this.width; t += 25) {
                    var i = this.buffer.get(t, e),
                         a = [2 * i[0] % 100, i[1], i[2], 128],
                         i = int(random(0, 20));
                    this.buffer.stroke(a), this.buffer.fill(a), this.buffer.rect(t, e, 20 + i, cfg.resRatio), t += i
               }
     }
}
let shards;

function initShards() {
     shards = calcShards()
}

function drawShard(t, e) {
     return t.colorMode(HSB, 100), e %= shards.length, t = drawOneShard(t, shards[e])
}

function drawOneShard(t, e) {
     t.strokeWeight(cfg.resRatio), t.stroke(e.hue, 100, 80, 80), t.fill(e.fill), cfg.tick % 10 == 0 ? t.blendMode(OVERLAY) : t.blendMode(BLEND);
     var i = e.startAngle * cfg.tick * .2,
          a = e.endAngle * cfg.tick * .2;
     return t.arc(cfg.hw, cfg.hw, e.rad, e.rad, i, a), t
}

function drawAllShards(t) {
     t.background(cfg.startHue, 100, 30), shards = shards || calcShards();
     for (var e of shards) drawOneShard(t, e);
     return t
}
const calcShards = () => {
          shards = [];
          let e = cfg.startHue;
          cfg.minShardLength = cfg.canvaSize * cfg.minShardMul, cfg.maxShardLength = cfg.canvaSize * cfg.maxShardMul, cfg.shardWidth = .1 * cfg.totalSteps, cfg.shardSteps = cfg.maxShardSteps;
          var i = map(dcp[0], 0, 256, 0, 100);
          for (let t = 0; t < cfg.shardCount; t++) {
               var a = getStep(t);
               e = (e + cfg.hueStep) % 100;
               var s = map(a, 0, 256, cfg.minShardLength, cfg.maxShardLength),
                    r = 2 * PI / cfg.shardSteps,
                    c = r * t + i,
                    a = c + cfg.shardWidth * r,
                    r = [e, cfg.shardColors[0], cfg.shardColors[1], cfg.shardColors[2]],
                    a = {
                         idx: t,
                         fill: r,
                         hue: e,
                         rad: s,
                         startAngle: c,
                         endAngle: a
                    };
               shards.push(a)
          }
          return shards
     },
     swooshOpts = {
          fuzziness: 0,
          modAmount: 1,
          ringsCount: 1,
          ringGaps: [.1, .3, .31, .33],
          weights: [1, 7],
          lineProps: [
               [100, 80, 100],
               [100, 50, 30]
          ],
          maxCurveSteps: 0,
          minRingVolume: .1
     };
class PolarPoint {
     constructor(t, e) {
          this.angle = t, this.radius = e, this.calc(e)
     }
     calc(t) {
          var {
               x: e,
               y: t
          } = polarToCart(this.angle, t);
          this.x = e + cfg.hw, this.y = t + cfg.hw
     }
     modulate(t, e, i) {
          var a = swooshOpts.modAmount * cfg.resRatio,
               e = (t + e) * cfg.canvaSize + i % 2 * .05;
          this.calc(e += i % 2 * a)
     }
}

function polarToCart(t, e) {
     return t %= 360, {
          x: e * Math.cos(t),
          y: e * Math.sin(t)
     }
}
let points;

function initSwoosh() {
     points = calcPath()
}

function drawSwoosh(i, a) {
     a.blendMode(LIGHTEST);
     var s = points,
          r = swooshOpts.weights,
          c = swooshOpts.lineProps;
     let o = 0;
     for (let e = 0; e <= swooshOpts.ringsCount; e++)
          for (let t = 0; t < 2; t++) {
               a.beginShape();
               for (var n of s) {
                    var h = i % cfg.totalSteps,
                         d = map(h, 0, cfg.totalSteps, 0, 100);
                    a.noFill();
                    h = c[t];
                    a.stroke(d, h[0], h[1], h[2]), a.strokeWeight(r[t] * cfg.resRatio);
                    h = swooshOpts.ringGaps[e];
                    o++, n.modulate(cfg.volume, h, o);
                    a.curveVertex(n.x + 0, n.y + 0)
               }
               a.endShape(CLOSE)
          }
}

function calcPath() {
     let e = [];
     var i = 2 * cfg.totalSteps,
          a = Math.PI / cfg.totalSteps;
     for (let t = 0; t < i; t++) {
          var s = t * a,
               r = cfg.hw,
               r = new PolarPoint(s, r);
          e.push(r)
     }
     return e
}
class TextHex {
     constructor(t, e, i, a, s) {
          this.text = t, this.angle = e + a;
          i = polarToCart(e, this.radius = i);
          this.py = i.y + cfg.hw, this.px = i.x + cfg.hw;
          i = map(dcp[12], 0, 100, 0, 70, !0);
          this.hue = (i + 2 * s) % 100
     }
     draw(t, e) {
          var i = (this.hue + cfg.tick) % 100;
          t.textSize(cfg.textSize), t.push(), t.translate(this.px, this.py), t.rotate(this.angle + HALF_PI), t.strokeWeight(0), t.fill(i, 50, 100, 70), t.text(this.text, 0, 0), t.pop()
     }
}
let textBlocks;
const initText = () => {
          var e = dcp[3];
          textBlocks = [];
          var i = cfg.textAngleStep,
               a = .75 * cfg.hw;
          cfg.textSize = cfg.canvaSize * cfg.textSizeRatio;
          for (let t = 0; t < hashPairs.length; t++) {
               var s = hashPairs[t],
                    r = String(s),
                    c = t * i + e,
                    s = +PI / hashPairs.length,
                    s = new TextHex(r, c, a, s, t);
               textBlocks.push(s)
          }
     },
     drawAllText = (e, i) => (e.colorMode(HSB, 100), textBlocks.map(t => {
          t.draw(e, i)
     }), e);

function initHashes() {
     hashPairs = [];
     for (let t = 0; t < 32; t++) hashPairs.push(tokenData.hash.slice(2 + 2 * t, 4 + 2 * t));
     dcp = hashPairs.map(t => parseInt(t, 16)), dcp.push(dcp[0]), seed = parseInt(tokenData.hash.slice(0, 16), 16), cfg.startHue = map(dcp[0], 0, 256, 0, 100), cfg.endHue = map(dcp[1], 0, 256, 0, 100), cfg.shardWidth = cfg.shardWidth || map(dcp[3], 0, 256, 0, 5);
     var e = hashPairs.length / 2,
          i = hashPairs.length / 5;
     hashBlocks = [];
     let a = 0;
     for (let t = 0; t <= e; t++) {
          let e = "";
          for (let t = 0; t <= i; t++) {
               a++;
               var s = hashPairs[a];
               s && (e += s)
          }
          hashBlocks[t] = e
     }
}
let numberOfShapes = 15,
     speed;
const clog = () => {},
     windowPadding = 0;
let hashPairs, hashBlocks, dcp, seed, count = 0,
     shardStep = 0,
     shardBuffer, mbuf, glitch, cfg = {
          hw: 0,
          imageRenderTicks: 32,
          resExpect: 512,
          resRatio: 0,
          fillSwoosh: !0,
          lineSwoosh: !1,
          minSwooshRadMul: .2,
          maxSwooshRadMul: .5,
          maxCount: 3,
          startHue: 0,
          endHue: 0,
          hueStep: 0,
          hueRange: 0,
          startSat: 80,
          startBri: 50,
          totalSteps: 0,
          canvaSize: 0,
          shards: !0,
          minShardMul: .1,
          maxShardMul: 1.5,
          shardCount: 15,
          shardWidth: 3,
          minShardLength: 0,
          maxShardLength: 0,
          shardSteps: 0,
          maxShardSteps: 8,
          shardColors: [95, 60, 40],
          minSwooshRad: 1,
          maxSwooshRad: 20,
          textSize: 32,
          lineHeight: 48,
          textAngleStep: .02 * Math.PI,
          textSizeRatio: .02,
          tick: 0,
          paused: !1,
          startGlitchPct: 5,
          glitchPct: 1,
          vSpace: 10,
          volume: 0,
          sinEffect: 150
     };

function setup() {
     clog("🚀 ready"), initHashes();
     var t = (windowWidth < windowHeight ? windowWidth : windowHeight) - windowPadding;
     createCanvas(t, t);
     cfg.canvaSize = t, rectMode(CENTER).noFill().frameRate(30), initDrawing()
}

function initDrawing() {
     var t = cfg.canvaSize;
     mbuf = createGraphics(cfg.canvaSize, cfg.canvaSize), mbuf.colorMode(HSB, 100), shardBuffer = createGraphics(cfg.canvaSize, cfg.canvaSize), shardBuffer.colorMode(HSB, 100), cfg.hw = t / 2, cfg.totalSteps = dcp.length, cfg.canvaSize = t, cfg.tick = 0, cfg.textSize = t / 30, cfg.lineHeight = 1.2 * cfg.textSize, cfg.startHue = map(dcp[10], 0, 256, 0, 80);
     t = cfg.startHue;
     cfg.hueRange = map(dcp[5], 0, 256, 50, 200), cfg.endHue = t + cfg.hueRange, cfg.hueStep = cfg.hueRange / cfg.totalSteps, cfg.resRatio = cfg.canvaSize / 512, initShards(), initSwoosh(), initText(), clog("initDrawing.done"), shardStep = 0, count = 0, blendMode(BLEND), mbuf.background(cfg.startHue, cfg.startSat, cfg.startBri), mbuf.image(shardBuffer, 0, 0), glitch = new Glitch(mbuf, 0), glitch.pause(!0);
     for (let t = 0; t < cfg.imageRenderTicks; t++) render();
     glitch.pause(!1), map(dcp[10], 0, 256, 0, 100) < cfg.startGlitchPct && (t = map(dcp[10], 0, 256, .1 * cfg.canvaSize, .9 * cfg.canvaSize), glitch.pause(!1), glitch.setLine(t), glitch.start(60), glitch.render(), glitch.render(), glitch.render()), blendMode(BLEND), image(mbuf, 0, 0), cfg.paused && noLoop(), AudioInput.initAudio()
}

function getStep(t) {
     return t %= dcp.length, dcp[t]
}

function draw() {
     render()
}

function showFrame() {
     mbuf.fill(255), mbuf.strokeWeight(0), mbuf.rect(0, 0, 100, 50), mbuf.fill(0), mbuf.text(cfg.tick, 10, 30)
}

function render(t = 0) {
     t = t || cfg.tick++, count % 3 == 0 && (shardStep++, drawShard(shardBuffer, shardStep), mbuf.blendMode(BLEND), mbuf.image(shardBuffer, 0, 0)), cfg.tick % 2 == 1 && drawAllText(mbuf, count), glitch.check(), blendMode(BLEND), image(mbuf, 0, 0), drawSwoosh(count, mbuf), count++
}

function mouseClicked(t) {
     return console.log("evt", t), glitch.setLine(t.clientY), glitch.start(), AudioInput.initAudio(), !1
}

function pause(t) {
     cfg.paused = !cfg.paused, (cfg.paused ? noLoop : loop)(), t && t.stopPropagation()
}