<!DOCTYPE html>
<html>
<head>
<script src="/content/7e37766541506810ba6399c4b2735121f508bd9209df43dd200bf2316b014594i0"></script>
<script src="/content/c192f63c1990ee1377d51de1f5b6820eac412aa779d717b9497806a072ea49f6i0"></script>	
<!-- artwork by @billythecatsbtc -->
<style>
body {
   margin: 0;
   padding: 0;
   display: flex;
   flex-direction: column;
   justify-content: flex-start;
   align-items: flex-start;
   height: 100%;
   background-color: #f0f0f0;
   overflow: auto;
}
#controls {
   width: 100%;
   background-color: rgba(255, 255, 255, 0.8);
   box-sizing: border-box;
   z-index: 10;
   position: absolute;
   top: 0;
}
#canvas-container {
   flex: 1;
   width: 100%;
   height: 100%;
}
canvas {
   display: block;
}
</style>
</head>
<body>
<div id="controls">
<input id="blk" type="number" placeholder="Enter block number" />
</div>
<div id="canvas-container"></div>
<script>
let canvas;
let blockNumber = 1;
const BASE_SIZE = 1000;

class DeterministicGenerator {
    constructor(seed) {
        this.seed = seed;
        Math.seedrandom(seed.toString());
        noiseSeed(seed);
    }
    getValue(x, y = 0, z = 0) {
        const nx = (x % BASE_SIZE) / BASE_SIZE;
        const ny = (y % BASE_SIZE) / BASE_SIZE;
        const nz = z;
        return noise(nx * 100, ny * 100, nz * 100);
    }
    
    getRange(min, max, x, y = 0, z = 0) {
        return min + this.getValue(x, y, z) * (max - min);
    }
    
    getInt(min, max, x, y = 0, z = 0) {
        return Math.floor(this.getRange(min, max + 1, x, y, z));
    }
    
    reseed(seed) {
        this.seed = seed;
        Math.seedrandom(seed.toString());
        noiseSeed(seed);
    }
}

const colorPalettes = [
    ['#FF6B6B', '#FFD93D', '#6BCB77', '#4D96FF', '#F07E58', '#FF9EAA', '#FFE5E5'],
    ['#2C3639', '#3F4E4F', '#A27B5C', '#DCD7C9', '#E9B384', '#7D6167'],
    ['#001524', '#15616D', '#FFECD1', '#FF7D00', '#78290F', '#001524'],
    ['#D7E4C0', '#BBC3A4', '#A6B07E', '#7C8363', '#5C6148', '#3E432E'],
    ['#C2DED1', '#ECE5C7', '#CDC2AE', '#354259', '#783937', '#E8D5C4'],
    ['#1A374D', '#406882', '#6998AB', '#B1D0E0', '#EA5455', '#FFB562'],
    ['#393232', '#4D4545', '#8D7B68', '#A4907C', '#C8B6A6', '#F1DEC9'],
    ['#2D033B', '#810CA8', '#C147E9', '#E5B8F4', '#9D3C72', '#FAEDCD']
];

let gen;

function getScaleFactor() {
    return min(width, height) / BASE_SIZE;
}

function setup() {
    let canvasSize = min(windowWidth, windowHeight);
    canvas = createCanvas(canvasSize, canvasSize);
    canvas.parent('canvas-container');
    
    gen = new DeterministicGenerator(blockNumber);
    noLoop();
    generateArt();
    document.getElementById('blk').value = blockNumber;
    document.getElementById('blk').addEventListener('input', updateArt);
    window.addEventListener('resize', resize, true);
}

function generateArt() {
    clear();
    const scaleFactor = getScaleFactor();
    let palette = colorPalettes[blockNumber % colorPalettes.length];
    createLayeredBackground(palette, scaleFactor);
    addNoiseTexture(scaleFactor);
    
    const layers = 12;  
    generateOrganicShapes(layers, palette, scaleFactor);
        
    addDetailElements(scaleFactor, palette);
    
    if (String(blockNumber).includes('123')) {
        btc(width / 2, height / 2, scaleFactor);
    }
    
    if (String(blockNumber).includes('44') || 
        String(blockNumber).includes('55') || 
        String(blockNumber).includes('66')) {
        const angle = gen.getValue(0) * TWO_PI;
        const radius = gen.getValue(1) * BASE_SIZE * 0.023 * scaleFactor;
        const eyeX = width / 2 + cos(angle) * radius;
        const eyeY = height / 2 + sin(angle) * radius;
        Eye(eyeX, eyeY, BASE_SIZE * 0.023 * 1.5, scaleFactor);
    }
    
    if (String(blockNumber).includes('77') || 
        String(blockNumber).includes('88') || 
        String(blockNumber).includes('99')) {
        bitmap(width / 2, height / 2, scaleFactor);
    }
}

function createLayeredBackground(palette, scaleFactor) {    
    const gradientLayers = 3;
    for (let i = 0; i < gradientLayers; i++) {
        const c1 = color(palette[i % palette.length]);
        const c2 = color(palette[(i + 1) % palette.length]);
        c1.setAlpha(150);
        c2.setAlpha(150);
        setGradient(0, 0, width, height, c1, c2, i * TWO_PI / gradientLayers);
    }
   
    stroke(255, 15);
    const patternDensity = BASE_SIZE * 0.1 * scaleFactor;
    for (let i = 0; i < width; i += patternDensity) {
        const noiseVal = gen.getValue(i * 0.01) * height;
        line(i, 0, i + noiseVal, height);
    }
}

function addNoiseTexture(scaleFactor) {
    loadPixels();
    const d = pixelDensity();
    const factor = 0.1 * scaleFactor;
    
    for (let x = 0; x < width * d; x++) {
        for (let y = 0; y < height * d; y++) {
            const index = 4 * (y * width * d + x);
            const noise = gen.getValue(x * factor, y * factor) * 255 * 0.1;
            pixels[index] = constrain(pixels[index] + noise, 0, 255);
            pixels[index + 1] = constrain(pixels[index + 1] + noise, 0, 255);
            pixels[index + 2] = constrain(pixels[index + 2] + noise, 0, 255);
        }
    }
    updatePixels();
}

function generateOrganicShapes(layers, palette, scaleFactor) {
    const baseRadius = BASE_SIZE * 0.023;
    
    for (let layer = 0; layer < layers; layer++) {
        const numShapes = floor(map(layer, 0, layers - 1, 8, 180));
        const radiusVariation = map(layer, 0, layers - 1, baseRadius, BASE_SIZE * 0.25) * scaleFactor;
        const staticOffset = gen.getValue(layer) * BASE_SIZE * 0.12 * scaleFactor;
        
        for (let i = 0; i < numShapes; i++) {
            const angle = map(i, 0, numShapes, 0, TWO_PI) + gen.getValue(layer, i) * 0.8;
            const radius = radiusVariation * (1 + gen.getValue(i, layer) * 0.7);
            
            const x = width / 2 + cos(angle) * (radius + staticOffset);
            const y = height / 2 + sin(angle) * (radius + staticOffset);
            
            const shapeSize = gen.getRange(radiusVariation * 0.2, radiusVariation * 1.1, i, layer);
            const colorIndex = floor(gen.getValue(i, layer) * palette.length);
            const shapeColor = color(palette[colorIndex]);
            
            drawEnhancedShape(x, y, shapeSize, shapeColor, scaleFactor, i, layer);
        }
    }
}

function drawEnhancedShape(x, y, size, shapeColor, scaleFactor, seedX, seedY) {
    push();
    translate(x, y);
    const rotation = gen.getValue(seedX, seedY) * TWO_PI;
    rotate(rotation);
    
    drawingContext.shadowOffsetX = 6 * scaleFactor;
    drawingContext.shadowOffsetY = 6 * scaleFactor;
    drawingContext.shadowBlur = 15 * scaleFactor;
    drawingContext.shadowColor = 'rgba(0, 0, 0, 0.35)';
    
    const shapeType = gen.getValue(seedX * 2, seedY * 2);
    
    if (shapeType < 0.33) {
        drawOrganicBlob(size, shapeColor, scaleFactor);
    } else if (shapeType < 0.66) {
        drawCrystalline(size, shapeColor, scaleFactor);
    } else {
        drawSpiral(size, shapeColor, scaleFactor);
    }
    
    pop();
}

function drawOrganicBlob(size, shapeColor, scaleFactor) {
    const points = 12;
    const angleStep = TWO_PI / points;
    
    beginShape();
    for (let i = 0; i <= points; i++) {
        const angle = i * angleStep;
        const noise = gen.getValue(cos(angle), sin(angle)) * size * 0.3;
        const radius = size / 2 + noise;
        const x = cos(angle) * radius;
        const y = sin(angle) * radius;
        curveVertex(x, y);
    }
    endShape(CLOSE);
    
    const innerSize = size * 0.7;
    fill(shapeColor.levels[0], shapeColor.levels[1], shapeColor.levels[2], 150);
    drawingContext.shadowColor = 'rgba(0, 0, 0, 0)';
    
    beginShape();
    for (let i = 0; i <= points; i++) {
        const angle = i * angleStep + PI / 6;
        const noise = gen.getValue(cos(angle) * 2, sin(angle) * 2) * innerSize * 0.3;
        const radius = innerSize / 2 + noise;
        const x = cos(angle) * radius;
        const y = sin(angle) * radius;
        curveVertex(x, y);
    }
    endShape(CLOSE);
}

function drawCrystalline(size, shapeColor, scaleFactor) {
    const segments = floor(gen.getRange(6, 12, size));
    const angleStep = TWO_PI / segments;
    
    for (let i = 0; i < segments; i++) {
        const angle = i * angleStep;
        const nextAngle = (i + 1) * angleStep;
        
        const r1 = size * (0.3 + gen.getValue(i, 0) * 0.3);
        const r2 = size * (0.3 + gen.getValue(i + 1, 0) * 0.3);
        
        const x1 = cos(angle) * r1;
        const y1 = sin(angle) * r1;
        const x2 = cos(nextAngle) * r2;
        const y2 = sin(nextAngle) * r2;
        
        fill(shapeColor);
        triangle(0, 0, x1, y1, x2, y2);
        
        const innerColor = color(shapeColor.toString());
        innerColor.setAlpha(150);
        fill(innerColor);
        
        const ri1 = r1 * 0.7;
        const ri2 = r2 * 0.7;
        const xi1 = cos(angle) * ri1;
        const yi1 = sin(angle) * ri1;
        const xi2 = cos(nextAngle) * ri2;
        const yi2 = sin(nextAngle) * ri2;
        
        triangle(0, 0, xi1, yi1, xi2, yi2);
    }
}

function drawSpiral(size, shapeColor, scaleFactor) {
    const turns = 5;
    const points = 180;
    
    for (let i = 0; i < points; i++) {
        const angle = map(i, 0, points, 0, TWO_PI * turns);
        const radius = map(i, 0, points, 0, size / 2);
        const x = cos(angle) * radius;
        const y = sin(angle) * radius;
        
        const dotSize = map(i, 0, points, 8 * scaleFactor, 2 * scaleFactor);
        const alpha = map(i, 0, points, 255, 100);
        
        fill(red(shapeColor), green(shapeColor), blue(shapeColor), alpha);
        circle(x, y, dotSize);
    }
}

function addDetailElements(scaleFactor, palette) {
    const numParticles = 100;
    for (let i = 0; i < numParticles; i++) {
        const x = gen.getValue(i, 0) * width;
        const y = gen.getValue(i, 1) * height;
        const size = gen.getValue(i, 2) * 3 * scaleFactor;
        
        fill(255, 100);
        noStroke();
        circle(x, y, size);
    }
}

function setGradient(x, y, w, h, c1, c2, angle = 0) {
    push();
    translate(width / 2, height / 2);
    rotate(angle);
    translate(-width / 2, -height / 2);
    
    for (let i = y; i <= y + h; i++) {
        const inter = map(i, y, y + h, 0, 1);
        const noiseVal = gen.getValue(i * 0.01) * 0.15;
        const c = lerpColor(c1, c2, inter + noiseVal);
        stroke(c);
        line(x, i, x + w, i);
    }
    pop();
}

function btc(x, y, scaleFactor) {
    const size = BASE_SIZE * 0.04 * scaleFactor;
    noStroke();
    fill('#ffa500');
    ellipse(x, y, size, size);
    fill('#FFFFFF');
    textSize(size / 1.3);
    textAlign(CENTER, CENTER);
    text('\u20BF', x, y);
}

function Eye(x, y, eyeSize, scaleFactor) {
    push();
    translate(x, y);
    
    noStroke();
    eyeSize *= scaleFactor;
    fill(255);
    ellipse(0, 0, eyeSize, eyeSize * 0.7);
 
    const irisSize = eyeSize * 0.45;
    const irisColor = color('#3B82F6');
    
    for (let i = irisSize; i > 0; i -= 0.5 * scaleFactor) {
        const inter = map(i, irisSize, 0, 0, 1);
        const c = lerpColor(irisColor, color(0), inter);
        fill(c);
        ellipse(0, 0, i, i);
    }
    
    pop();
}

function bitmap(x, y, scaleFactor) {
    const size = BASE_SIZE * 0.05 * scaleFactor;
    const cornerRadius = 5 * scaleFactor;
    fill('#FFA500');
    noStroke();
    rectMode(CENTER);
    rect(x, y, size, size, cornerRadius);
}

function updateArt() {
    blockNumber = parseInt(document.getElementById('blk').value) || 1;
    gen.reseed(blockNumber);
    generateArt();
}

function resize() {
    let canvasSize = min(windowWidth, windowHeight);
    resizeCanvas(canvasSize, canvasSize);
    generateArt();
}

window.addEventListener('load', setup);
</script>
<script id="preview" mint="MINT_INSCRIPTION_ID"></script>
</body>
</html>