<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>上帝类 · 算法创世绘 | 自动生成艺术</title>
<style>
* {
box-sizing: border-box;
user-select: none;
}
body {
background: radial-gradient(circle at 20% 30%, #0f111f, #010207);
font-family: 'Segoe UI', 'Inter', system-ui, monospace;
min-height: 100vh;
padding: 1.5rem;
display: flex;
justify-content: center;
align-items: center;
}
.god-panel {
max-width: 1300px;
width: 100%;
background: rgba(14, 17, 30, 0.9);
backdrop-filter: blur(6px);
border-radius: 2rem;
box-shadow: 0 25px 45px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,215,130,0.2);
padding: 1.5rem;
}
h1 {
font-size: 1.9rem;
font-weight: 800;
background: linear-gradient(120deg, #FFE6B0, #B7C9FF);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.sub {
color: #a4afdf;
font-size: 0.8rem;
margin-bottom: 1.5rem;
border-left: 3px solid #ffb347;
padding-left: 14px;
}
.canvas-area {
background: #0a0c16;
border-radius: 1.5rem;
padding: 1rem;
box-shadow: inset 0 0 6px #00000040, 0 8px 20px black;
margin-bottom: 1.5rem;
}
canvas {
width: 100%;
height: auto;
background: white;
border-radius: 1rem;
box-shadow: 0 4px 12px rgba(0,0,0,0.5);
display: block;
}
.controls {
background: #0b0d19cc;
border-radius: 1.2rem;
padding: 1rem;
backdrop-filter: blur(4px);
}
.title-sm {
font-size: 0.9rem;
font-weight: 600;
color: #ffcd94;
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 8px;
}
.algo-selector {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 15px;
}
button {
background: #2a2f50;
border: none;
padding: 6px 16px;
border-radius: 40px;
font-weight: 600;
color: white;
font-size: 0.8rem;
cursor: pointer;
transition: 0.2s;
}
button.primary {
background: #ffa62e;
color: #1e1f2c;
}
button.primary:hover {
background: #ffbc62;
transform: scale(0.96);
}
button:hover {
background: #404871;
transform: translateY(-1px);
}
.param-slider {
margin: 12px 0;
}
.param-slider label {
font-size: 0.75rem;
color: #bfc8ff;
display: flex;
justify-content: space-between;
}
inputtype="range" {
width: 100%;
background: #2f3557;
height: 3px;
border-radius: 3px;
}
.status {
background: #00000066;
border-radius: 1rem;
padding: 6px 12px;
font-size: 0.7rem;
color: #ccd6ff;
margin-top: 12px;
text-align: center;
}
footer {
font-size: 0.7rem;
color: #6b729b;
text-align: center;
margin-top: 1rem;
}
</style>
</head>
<body>
<div class="god-panel">
<h1>🌀 上帝类 · 算法创世绘 🌀</h1>
<div class="sub">≡ 从白纸生成 · 分形/噪声/递归艺术 ≡</div>
<div class="canvas-area">
<canvas id="artCanvas" width="800" height="600" style="width:100%; height:auto; aspect-ratio:800/600;"></canvas>
</div>
<div class="controls">
<div class="title-sm">⚙️ 算法圣所</div>
<div class="algo-selector">
<button data-algo="fractalTree" class="primary">🌳 递归分形树</button>
<button data-algo="mandelbrot">🐚 曼德博集合</button>
<button data-algo="noiseWave">🌊 噪声波纹</button>
<button data-algo="sierpinski">🔺 谢尔宾斯基地毯</button>
<button data-algo="circlePacking">🔘 圆填充</button>
</div>
<div id="paramPanel" class="param-slider">
<label><span>🌿 递归深度 / 迭代次数</span><span id="depthValue">5</span></label>
<input type="range" id="depthSlider" min="1" max="12" step="1" value="5">
</div>
<div class="status" id="statusMsg">⚡ 上帝算法待命 | 选择一种创世法则</div>
</div>
<footer>🎨 全知全能生成 | 每个算法自动在白纸上绘制神迹 | 无需手动画一笔</footer>
</div>
<script>
// ======================== 上帝类:算法自动绘图核心 ========================
class ArtGenesisGod {
constructor() {
this.canvas = document.getElementById('artCanvas');
this.ctx = this.canvas.getContext('2d');
this.width = 800;
this.height = 600;
this.canvas.width = this.width;
this.canvas.height = this.height;
// 当前选中的算法
this.currentAlgo = 'fractalTree';
// 参数
this.depth = 5; // 递归深度 / 迭代次数
this.maxDepth = 12;
// DOM 元素
this.algoBtns = document.querySelectorAll('data-algo');
this.depthSlider = document.getElementById('depthSlider');
this.depthValueSpan = document.getElementById('depthValue');
this.statusDiv = document.getElementById('statusMsg');
this.initEvents();
// 初始绘制默认算法
this.draw();
}
initEvents() {
// 算法切换
this.algoBtns.forEach(btn => {
btn.addEventListener('click', (e) => {
this.currentAlgo = btn.dataset.algo;
// 更新按钮高亮
this.algoBtns.forEach(b => b.classList.remove('primary'));
btn.classList.add('primary');
this.draw();
});
});
// 深度/迭代滑动条
this.depthSlider.addEventListener('input', (e) => {
this.depth = parseInt(e.target.value);
this.depthValueSpan.innerText = this.depth;
this.draw();
});
}
updateStatus(msg) {
this.statusDiv.innerHTML = `✨ ${msg}`;
setTimeout(() => {
if (this.statusDiv.innerHTML === `✨ ${msg}`) {
// 保持静默
}
}, 2000);
}
// 清空白纸(填充白色)
clearCanvas() {
this.ctx.fillStyle = '#FFFFFF';
this.ctx.fillRect(0, 0, this.width, this.height);
}
// 核心:根据算法调用对应绘制函数
draw() {
this.clearCanvas();
switch (this.currentAlgo) {
case 'fractalTree':
this.drawFractalTree();
break;
case 'mandelbrot':
this.drawMandelbrot();
break;
case 'noiseWave':
this.drawNoiseWave();
break;
case 'sierpinski':
this.drawSierpinskiCarpet();
break;
case 'circlePacking':
this.drawCirclePacking();
break;
default:
this.drawFractalTree();
}
this.updateStatus(`已显圣 · {this.getAlgoName(this.currentAlgo)} \| 深度/迭代: {this.depth}`);
}
getAlgoName(algo) {
const map = {
fractalTree: '递归分形树',
mandelbrot: '曼德博集合',
noiseWave: '噪声波纹',
sierpinski: '谢尔宾斯基地毯',
circlePacking: '圆填充'
};
return mapalgo || algo;
}
// ---------- 算法 1: 递归分形树 (彩色渐变) ----------
drawFractalTree() {
const startX = this.width / 2;
const startY = this.height - 50;
const startLen = 100;
const angle = -Math.PI / 2; // 向上
const branchAngle = Math.PI / 6; // 分支角度30度
const shrink = 0.67; // 长度缩减比例
this.ctx.save();
this.ctx.translate(startX, startY);
this.drawBranch(this.depth, startLen, angle, branchAngle, shrink);
this.ctx.restore();
}
drawBranch(depth, length, angle, branchAngle, shrink) {
if (depth === 0 || length < 2) return;
const x2 = Math.cos(angle) * length;
const y2 = Math.sin(angle) * length;
// 绘制树干/分支
this.ctx.beginPath();
this.ctx.moveTo(0, 0);
this.ctx.lineTo(x2, y2);
// 颜色:根据深度渐变 (棕色 -> 绿色)
const greenIntensity = 0.3 + (depth / this.maxDepth) * 0.6;
const r = 100 + (this.maxDepth - depth) * 12;
const g = 70 + depth * 15;
const b = 40;
this.ctx.strokeStyle = `rgb({r}, {g}, ${b})`;
this.ctx.lineWidth = Math.max(1, depth * 1.2);
this.ctx.stroke();
// 递归左分支 & 右分支
this.ctx.save();
this.ctx.translate(x2, y2);
this.drawBranch(depth - 1, length * shrink, angle - branchAngle, branchAngle, shrink);
this.drawBranch(depth - 1, length * shrink, angle + branchAngle, branchAngle, shrink);
this.ctx.restore();
// 叶子效果: 最后一级绘制小圆点
if (depth === 1) {
this.ctx.beginPath();
this.ctx.arc(x2, y2, 3, 0, Math.PI * 2);
this.ctx.fillStyle = `rgb(255, ${120 + depth * 30}, 80)`;
this.ctx.fill();
}
}
// ---------- 算法 2: 曼德博集合 (经典分形) ----------
drawMandelbrot() {
const maxIter = Math.min(200, Math.max(20, this.depth * 15));
const xMin = -2.5, xMax = 1;
const yMin = -1.2, yMax = 1.2;
const imageData = this.ctx.createImageData(this.width, this.height);
for (let py = 0; py < this.height; py++) {
for (let px = 0; px < this.width; px++) {
const x0 = xMin + (px / this.width) * (xMax - xMin);
const y0 = yMin + (py / this.height) * (yMax - yMin);
let x = 0, y = 0;
let iter = 0;
while (x*x + y*y <= 4 && iter < maxIter) {
const xt = x*x - y*y + x0;
y = 2*x*y + y0;
x = xt;
iter++;
}
const color = iter === maxIter ? 0 : 255 - (iter / maxIter) * 255;
const hue = (iter / maxIter) * 360;
const sat = 0.8;
const light = iter === maxIter ? 0 : 0.6;
const rgb = this.hslToRgb(hue, sat, light);
const idx = (py * this.width + px) * 4;
if (iter === maxIter) {
imageData.dataidx = 0;
imageData.dataidx+1 = 0;
imageData.dataidx+2 = 0;
} else {
imageData.dataidx = rgb0;
imageData.dataidx+1 = rgb1;
imageData.dataidx+2 = rgb2;
}
imageData.dataidx+3 = 255;
}
}
this.ctx.putImageData(imageData, 0, 0);
}
hslToRgb(h, s, l) {
let r, g, b;
if (s === 0) {
r = g = b = l;
} else {
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h / 360 + 1/3);
g = hue2rgb(p, q, h / 360);
b = hue2rgb(p, q, h / 360 - 1/3);
}
return Math.round(r \* 255), Math.round(g \* 255), Math.round(b \* 255);
}
// ---------- 算法 3: 噪声波纹 (基于正弦+余弦的抽象图案) ----------
drawNoiseWave() {
const freq = 0.02 + this.depth * 0.005;
const time = 0; // 静态图案
for (let y = 0; y < this.height; y++) {
for (let x = 0; x < this.width; x++) {
const nx = x / this.width;
const ny = y / this.height;
// 多组波形叠加
const val1 = Math.sin(nx * Math.PI * 8 * (this.depth/3)) * Math.cos(ny * Math.PI * 8);
const val2 = Math.sin((nx * 15 + ny * 10) * freq * 20);
const val3 = Math.sin(ny * 20 * freq * 10) * Math.cos(nx * 15);
let intensity = (val1 + val2 + val3) / 2.2;
intensity = (intensity + 1) / 2; // 0-1
const hue = (intensity * 360 + (nx * 180)) % 360;
const sat = 0.7;
const light = 0.5 + intensity * 0.3;
const rgb = this.hslToRgb(hue, sat, light);
const idx = (y * this.width + x) * 4;
this.ctx.fillStyle = `rgb({rgb\[0\]}, {rgb1}, ${rgb2})`;
this.ctx.fillRect(x, y, 1, 1);
}
}
}
// ---------- 算法 4: 谢尔宾斯基地毯 (递归方块) ----------
drawSierpinskiCarpet() {
const size = Math.min(this.width, this.height) * 0.8;
const startX = (this.width - size) / 2;
const startY = (this.height - size) / 2;
this.ctx.fillStyle = '#000000';
this.ctx.fillRect(startX, startY, size, size);
this.drawCarpet(startX, startY, size, this.depth);
}
drawCarpet(x, y, size, depth) {
if (depth === 0) return;
const newSize = size / 3;
// 中间挖空 (白色)
this.ctx.fillStyle = '#FFFFFF';
this.ctx.fillRect(x + newSize, y + newSize, newSize, newSize);
// 递归周围8个格子
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (i === 1 && j === 1) continue;
this.drawCarpet(x + i * newSize, y + j * newSize, newSize, depth - 1);
}
}
}
// ---------- 算法 5: 圆填充 (随机生成不重叠的圆,用颜色渐变) ----------
drawCirclePacking() {
const circles = \[\];
const minRadius = 5;
const maxRadius = 50;
const targetCount = 180 + this.depth * 20;
const maxAttempts = 5000;
let attempts = 0;
while (circles.length < targetCount && attempts < maxAttempts) {
const radius = minRadius + Math.random() * (maxRadius - minRadius) * (1 - circles.length / targetCount * 0.5);
const x = radius + Math.random() * (this.width - 2 * radius);
const y = radius + Math.random() * (this.height - 2 * radius);
let overlapping = false;
for (let c of circles) {
const dx = c.x - x;
const dy = c.y - y;
const dist = Math.sqrt(dx*dx + dy*dy);
if (dist < c.radius + radius) {
overlapping = true;
break;
}
}
if (!overlapping) {
circles.push({ x, y, radius });
}
attempts++;
}
// 绘制圆形,颜色基于位置和半径
for (let c of circles) {
const hue = (c.x / this.width * 360 + c.y / this.height * 180) % 360;
const sat = 0.6 + (c.radius / maxRadius) * 0.4;
const light = 0.5 + (c.radius / maxRadius) * 0.3;
const rgb = this.hslToRgb(hue, sat, light);
this.ctx.beginPath();
this.ctx.arc(c.x, c.y, c.radius, 0, Math.PI * 2);
this.ctx.fillStyle = `rgb({rgb\[0\]}, {rgb1}, ${rgb2})`;
this.ctx.fill();
this.ctx.strokeStyle = '#ffffff';
this.ctx.lineWidth = 1;
this.ctx.stroke();
}
}
}
// 启动上帝类
window.addEventListener('DOMContentLoaded', () => {
window.artGod = new ArtGenesisGod();
});
</script>
</body>
</html>