{"name":"dev_PARTY #013","description":"Interactive NFT by @andriibakulin\n\n<code>\nconst ITEMS_COUNT = 48;\n\nlet gEntities = [];\nlet gSizeArea;\nlet gSizePoints, gSizeDashes;\nlet gDistance, gDistanceSqr;\n\n// MagicLogic\n\nclass Entity\n{\n    constructor(index, count, xOffset, yOffset, radius, direction)\n    {\n        const seq01 = index / count;\n\n        this.xOffset = xOffset;\n        this.yOffset = yOffset;\n        this.radius  = radius;\n        this.direction = direction;\n\n        this.color  = seq01 * 255;\n        this.offset = seq01 * Math.PI;\n        this.angel  = seq01 * Math.PI * 2;\n\n        this.power = new SmoothValue();\n\n        // Dynamic vars\n        this.circleX = this.circleY = null;\n        this.drawAtX = this.drawAtY = null;\n        this.colorV = null;\n    }\n\n    next(dt)\n    {\n        this.color  += dt * 128;\n        this.offset += dt;\n        this.angel  -= dt / 2;\n\n        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n        // Update dynamic attrs\n\n        const radius = gSizeArea * this.radius;\n\n        this.circleX = Math.sin(this.angel * this.direction) * radius;\n        this.circleY = Math.cos(this.angel * this.direction) * radius;\n\n        this.drawAtX = gSizeArea * this.xOffset + this.circleX;\n        this.drawAtY = gSizeArea * this.yOffset + this.circleY;\n\n        this.colorV = normalizeColorComp(this.color);\n\n        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n\n        let dstOffset = 0;\n\n        if (mouseIsPressed)\n        {\n            const dstLengthSqr = (mouseX-this.drawAtX)**2 + (mouseY-this.drawAtY)**2;\n\n            if (dstLengthSqr < gDistanceSqr)\n                dstOffset = Math.sqrt(dstLengthSqr) / gDistance;\n        }\n\n        if (dstOffset > 0)\n            this.power.update(1 - dstOffset, 1 * dt);\n        else\n            this.power.update(0, 2 * dt);\n    }\n\n    render()\n    {\n        const sizePoint033 = gSizePoints/3;\n\n        resetMatrix();\n        translate(this.drawAtX, this.drawAtY);\n\n        if (this.power.v > 0)\n        {\n            const pointsCount = 5;\n\n            for (let i=1; i<=pointsCount; i++)\n            {\n                const power = this.power.v * i * 0.33;\n                strokeWeight(sizePoint033 + pointsCount-i);\n                stroke(this.colorV, 255, 255);\n                point(this.circleX * power, this.circleY * power);\n            }\n        }\n\n        if (this.power.v > 0)\n        {\n            strokeWeight(sizePoint033);\n            stroke(this.colorV, 255, 255, 255 * (1-this.power.v));\n            line(0,0, -this.circleX * 3 * this.power.v, -this.circleY * 3 * this.power.v);\n        }\n        else\n        {\n            rotate(360 * this.angel);\n            strokeWeight(sizePoint033);\n            stroke(this.colorV, 255, 255);\n            line(0,0, 0,gSizeDashes * (1-this.power.v));\n        }\n\n        strokeWeight(gSizePoints);\n        point(0,0);\n    }\n}\n\n// Lifecycle\n\nfunction setup()\n{\n    updateConsts();\n    createCanvas(gSizeArea, gSizeArea);\n    background(0);\n\n    pixelDensity(1);\n    frameRate(60);\n    colorMode(HSB, 255);\n    angleMode(DEGREES);\n\n    for (let index=0; index<ITEMS_COUNT; index++)\n    {\n        for (let angel = 0; angel<360; angel += 120)\n        {\n            const x = 0.50 + sin(angel) * 0.2;\n            const y = 0.55 - cos(angel) * 0.2;\n            gEntities.push(new Entity(index, ITEMS_COUNT, x, y, 0.2, +1));\n        }\n    }\n}\n\nfunction windowResized()\n{\n    updateConsts();\n    resizeCanvas(gSizeArea, gSizeArea);\n}\n\nfunction draw()\n{\n    const dt = deltaTime/1000;\n\n    background(0);\n\n    for (const idx in gEntities)\n    {\n        const ent = gEntities[idx];\n        ent.next(dt);\n        ent.render();\n    }\n}\n\n// Helpers\n\nfunction updateConsts()\n{\n    gSizeArea     = getAreaSize();\n\n    gDistance     = gSizeArea / 3;\n    gDistanceSqr  = gDistance ** 2;\n\n    gSizePoints   = clamp(gSizeArea / 66,  5, 12);\n    gSizeDashes   = clamp(gSizeArea / 33, 10, 25);\n}\n\nfunction normalizeColorComp(v)\n{\n    v %= 256;\n    return v >= 0 ? v : v+256;\n}\n\nfunction getAreaSize()\n{\n    return Math.min(window.innerWidth, window.innerHeight);\n}\n\nfunction clamp(value, min, max)\n{\n    if (value < min) return min;\n    if (value > max) return max;\n    return value;\n}\n\n// Helpers : Smooth\n\nfunction smoothValue(v0, v1, delta)\n{\n    if (v0 === null)\n        return v1;\n\n    const dv = v1 - v0;\n    return Math.abs(dv) <= delta ? v1 : (dv < 0 ? v0 - delta : v0 + delta);\n}\n\nclass SmoothValue\n{\n    constructor(v=null)\n    {\n        this.v = v;\n    }\n\n    update(v, delta)\n    {\n        this.v = smoothValue(this.v, v, delta);\n    }\n}\n</code>","tags":["genart","codeart","interactive","procedural","generative","realtime","abstract","colorful","art","algorithmic","script","p5js","js","math"],"symbol":"OBJKT","artifactUri":"ipfs://QmWLBUhbYuuMgEyZ4kFKfRNwMbUBqrufDDXiinFdR1xnvN","displayUri":"ipfs://QmfYReZKwgDptQLhtx1F6p5WsRW4eMJE7m1GU592MrMt43","thumbnailUri":"ipfs://QmNrhZHUaEqxhyLfqoq1mtHSipkWHeT31LNHb1QEbDHgnc","creators":["tz1Ys42frYhgxHxXtqoY42GiuRPZ9ykbP86Y"],"formats":[{"uri":"ipfs://QmWLBUhbYuuMgEyZ4kFKfRNwMbUBqrufDDXiinFdR1xnvN","mimeType":"application/x-directory"}],"decimals":0,"isBooleanAmount":false,"shouldPreferSymbol":false}