{"name":"dev_PARTY #010","description":"Interactive NFT by @andriibakulin\n\n<code>\nlet gEntities = [];\n\nclass Entity\n{\n    constructor(x, y)\n    {\n        const distance = Math.sqrt(x**2 + y**2);\n        const winMinSize = Math.min(window.innerWidth, window.innerHeight);\n\n        this.x = x;\n        this.y = y;\n        this.r = 5 + 15 * distance / winMinSize;\n\n        this.rotation = 0;\n        this.rotSpeed = Math.sign(Math.random()-0.5) * Math.min(30 + distance/3, 75);\n        this.outRange = winMinSize / 16;\n\n        this.color = getAngle(x,y) / 360 * 255;\n        this.alpha = 255;\n    }\n\n    next(dt)\n    {\n        this.rotation += dt * this.rotSpeed;\n        this.color = this.normalizeColor(this.color - dt * 32);\n        this.alpha -= dt * 128;\n\n        return this.alpha > 0;\n    }\n\n    render()\n    {\n        resetMatrix();\n        translate(window.innerWidth/2, window.innerHeight/2);\n        rotate(this.rotation);\n\n        noStroke();\n        fill(this.color, 255, this.alpha);\n        circle(this.x, this.y, this.r);\n\n        for (let i=0; i<3; i++)\n        {\n            circle(this.x + this.getRandomOutRange(), this.y + this.getRandomOutRange(), this.r * 0.33);\n        }\n\n        strokeWeight(1);\n        stroke(this.color, 255, this.alpha * 0.5);\n        line(0,0, this.x, this.y);\n    }\n\n    getRandomOutRange()\n    {\n        return (Math.random() - 0.5) * this.outRange;\n    }\n\n    normalizeColor(color)\n    {\n        color %= 255;\n        return color < 0 ? color + 255 : color;\n    }\n}\n\nfunction setup()\n{\n    createCanvas(window.innerWidth, window.innerHeight)\n\n    pixelDensity(1);\n    frameRate(60);\n\n    colorMode(HSB, 255);\n    angleMode(DEGREES);\n\n    background(0);\n}\n\nfunction windowResized()\n{\n    resizeCanvas(window.innerWidth, window.innerHeight);\n}\n\nlet gEntityAddTimeout = 0;\n\nfunction draw()\n{\n    const dt = deltaTime/1000;\n\n    if (gEntityAddTimeout <= 0)\n    {\n        let x = mouseIsPressed ? mouseX - window.innerWidth  / 2 : 0;\n        let y = mouseIsPressed ? mouseY - window.innerHeight / 2 : 0;\n\n        gEntities.push(new Entity(x, y));\n\n        gEntityAddTimeout = 1/60;\n    }\n    else\n    {\n        gEntityAddTimeout -= dt;\n    }\n\n    background(0);\n\n    for (const idx in gEntities)\n    {\n        const ent = gEntities[idx];\n        ent.render();\n\n        if (!ent.next(dt))\n            gEntities.splice(idx,1);\n    }\n}\n\nfunction getAngle(x, y)\n{\n    const angle = Math.atan2(y, x);\n    const degrees = 180*angle/Math.PI;\n    return (360+Math.round(degrees))%360;\n}\n</code>","tags":["codeart","interactive","procedural","generative","generativeart","realtime","p5js","p5func"],"symbol":"OBJKT","artifactUri":"ipfs://QmQmrAuWZ8F62TXQPUVLCafyDuy2RjyGFvpwJyDaHmP5P1","displayUri":"ipfs://QmRBcgJYYryT4sZcoadz24yVwyKoohDmptqGd1GuCRLHTf","thumbnailUri":"ipfs://QmNrhZHUaEqxhyLfqoq1mtHSipkWHeT31LNHb1QEbDHgnc","creators":["tz1Ys42frYhgxHxXtqoY42GiuRPZ9ykbP86Y"],"formats":[{"uri":"ipfs://QmQmrAuWZ8F62TXQPUVLCafyDuy2RjyGFvpwJyDaHmP5P1","mimeType":"application/x-directory"}],"decimals":0,"isBooleanAmount":false,"shouldPreferSymbol":false}