<!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>