opencode是一种AI代码生成工具,相比于传统AI一问一答操作,opencode能够自动运行、检查、修改代码,效率提升极大。
使用以下提示词“julia集合是一种基于复数的分形集合,编写另一个html文件,生成不同C值的julia集合,要求包含两个滑块设置C值,包含一个输入框决定绘制分辨率”,就可以生成一个漂亮的网页,感兴趣的试试吧。
html代码如下
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" cOntent="width=device-width, initial-scale=1.0">
<title>Julia 集合生成器</title>
<style>
:root{
--bg1:#0b1020; --bg2:#101a33; --card:rgba(255,255,255,.055);
--line:rgba(255,255,255,.13); --tx:#e7edf8; --mut:#93a6c4;
--cy:#22d3ee; --pi:#f472b6; --am:#fbbf24; --gr:#4ade80;
}
*{box-sizing:border-box; margin:0; padding:0}
body{
font-family:"Segoe UI","Microsoft YaHei","PingFang SC",sans-serif;
background:linear-gradient(160deg,var(--bg1),var(--bg2) 60%,#0d1830);
color:var(--tx); min-height:100vh;
}
.wrap{max-width:1060px; margin:0 auto; padding:28px 22px 60px}
header{text-align:center; padding:18px 0 26px}
.kicker{color:var(--cy); letter-spacing:.3em; font-size:12px; font-weight:600}
h1{
font-size:clamp(26px,4.4vw,44px); font-weight:800; margin:10px 0 6px;
background:linear-gradient(90deg,#22d3ee,#4ade80,#fbbf24,#f472b6);
-webkit-background-clip:text; background-clip:text; color:transparent;
}
.sub{color:var(--mut); font-size:14.5px}
.sub code{color:var(--cy); font-family:Consolas,monospace; background:rgba(34,211,238,.1); padding:1px 7px; border-radius:6px}
.panel{
background:var(--card); border:1px solid var(--line); border-radius:16px;
padding:18px 22px; margin-bottom:18px;
}
.grid{display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:18px}
.ctl{}
.ctl label{display:flex; justify-content:space-between; align-items:baseline; margin-bottom:8px}
.ctl label .name{font-weight:700; font-size:14px}
.ctl label .val{
font-family:Consolas,monospace; color:var(--am); font-weight:700; font-size:15px;
background:rgba(251,191,36,.1); padding:2px 10px; border-radius:8px;
}
input[type=range]{
-webkit-appearance:none; appearance:none; width:100%; height:6px; border-radius:99px;
background:linear-gradient(90deg,rgba(34,211,238,.5),rgba(244,114,182,.5)); outline:none;
}
input[type=range]::-webkit-slider-thumb{
-webkit-appearance:none; appearance:none; width:18px; height:18px; border-radius:50%;
background:#fff; border:3px solid var(--cy); cursor:pointer;
}
input[type=number]{
width:100%; padding:9px 12px; border-radius:10px; border:1px solid var(--line);
background:rgba(0,0,0,.3); color:var(--tx); font-size:15px; font-family:Consolas,monospace; outline:none;
}
input[type=number]:focus{border-color:var(--cy)}
.presets{display:flex; flex-wrap:wrap; gap:8px; margin-top:14px}
.presets span{
padding:6px 13px; border-radius:999px; border:1px solid var(--line); font-size:13px;
cursor:pointer; color:#c6d6ec; transition:.18s;
}
.presets span:hover{border-color:var(--pi); color:var(--pi)}
.canvas-box{
position:relative; text-align:center;
}
canvas{
width:min(760px,100%); height:auto; border-radius:16px; border:1px solid var(--line);
background:#04050c; box-shadow:0 18px 60px rgba(0,0,0,.45);
}
.statusbar{
display:flex; flex-wrap:wrap; gap:8px 24px; justify-content:center; margin-top:14px;
color:var(--mut); font-size:13.5px; font-family:Consolas,monospace;
}
.statusbar b{color:var(--cy); font-weight:600}
.statusbar em{color:var(--gr); font-style:normal; font-weight:700}
.hint{text-align:center; color:var(--mut); font-size:13px; margin-top:10px}
.btn{
padding:8px 20px; border-radius:12px; border:1px solid var(--line); background:rgba(255,255,255,.06);
color:var(--tx); cursor:pointer; font-size:14px; font-weight:600; transition:.2s; font-family:inherit;
}
.btn.primary{background:linear-gradient(90deg,#0ea5e9,#22d3ee); color:#05242e; border:none}
.btn.primary:hover{filter:brightness(1.1)}
.btn:hover{border-color:var(--cy); color:var(--cy)}
details.notes{border:1px solid var(--line); border-radius:14px; margin-top:20px; background:rgba(0,0,0,.18); overflow:hidden}
details.notes summary{padding:13px 20px; cursor:pointer; font-weight:700; color:var(--cy)}
details.notes .inner{padding:4px 20px 16px; color:#c2d2e8; font-size:14px; line-height:1.8}
details.notes code{background:rgba(34,211,238,.12); color:var(--cy); padding:1px 6px; border-radius:6px; font-family:Consolas,monospace}
</style>
</head>
<body>
<div class="wrap">
<header>
<div class="kicker">FRACTAL · COMPLEX DYNAMICS</div>
<h1>Julia 集合生成器</h1>
<div class="sub">迭代 <code>z ← z² + c</code>,用两个滑块调节复数 <code>c = a + bi</code>,输入框控制绘制分辨率</div>
</header>
<div class="panel">
<div class="grid">
<div class="ctl">
<label>
<span class="name">C 实部 a</span>
<span class="val" id="reVal">-0.8</span>
</label>
<input type="range" id="cRe" min="-2" max="2" step="0.001" value="-0.8">
</div>
<div class="ctl">
<label>
<span class="name">C 虚部 b</span>
<span class="val" id="imVal">0.156</span>
</label>
<input type="range" id="cIm" min="-2" max="2" step="0.001" value="0.156">
</div>
<div class="ctl">
<label>
<span class="name">分辨率(每边像素)</span>
<span class="val" id="resVal">800</span>
</label>
<input type="number" id="resInput" min="128" max="2000" step="8" value="800">
</div>
<div class="ctl">
<label>
<span class="name">最大迭代次数</span>
<span class="val" id="iterVal">180</span>
</label>
<input type="range" id="iterInput" min="20" max="1000" step="10" value="180">
</div>
</div>
<div class="presets">
<span data-re="-0.8" data-im="0.156">经典 -0.8+0.156i</span>
<span data-re="-0.74543" data-im="0.11301">夹心蛋糕</span>
<span data-re="-0.70176" data-im="-0.3842">海马形</span>
<span data-re="-0.4" data-im="0.6">花椰菜</span>
<span data-re="0.285" data-im="0.01">红豆</span>
<span data-re="-0.835" data-im="-0.2321">蝴蝶结</span>
<span data-re="0.7885" data-im="-0.2">网络星云</span>
</div>
</div>
<div class="canvas-box">
<canvas id="cv"></canvas>
<div class="statusbar">
<span>C = <b id="statusC">-0.8 + 0.156i</b></span>
<span>分辨率 <b id="statusRes">800×800</b></span>
<span>迭代上限 <b id="statusIter">180</b></span>
<span>渲染耗时 <em id="statusTime">—</em></span>
</div>
<div class="hint">鼠标在图上移动:实时显示该点复坐标及逃逸迭代次数</div>
<div class="hint" id="hoverInfo"></div>
</div>
<details class="notes">
<summary>数学说明</summary>
<div class="inner">
对每个像素对应的复数 <code>z₀ = x + iy</code>,反复迭代 <code>zₙ₊₁ = zₙ² + c</code>。
若迭代值始终不逃出圆盘 <code>|z| > 2</code>,该点属于 Julia 集(深色)。
否则记录逃逸所需的迭代次数并平滑映射为颜色,形成外部的分形轮廓。
不同 <code>c</code> 值会生成截然不同的形状:连接、破碎、星云、海马……
</div>
</details>
</div>
<script>
(function(){
var XMIN=-1.8, XMAX=1.8, YMIN=-1.8, YMAX=1.8;
var cv=document.getElementById(&#39;cv&#39;);
var ctx=cv.getContext(&#39;2d&#39;);
var reSlider=document.getElementById(&#39;cRe&#39;);
var imSlider=document.getElementById(&#39;cIm&#39;);
var reValEl=document.getElementById(&#39;reVal&#39;);
var imValEl=document.getElementById(&#39;imVal&#39;);
var resInput=document.getElementById(&#39;resInput&#39;);
var resValEl=document.getElementById(&#39;resVal&#39;);
var iterInput=document.getElementById(&#39;iterInput&#39;);
var iterValEl=document.getElementById(&#39;iterVal&#39;);
var statusC=document.getElementById(&#39;statusC&#39;);
var statusRes=document.getElementById(&#39;statusRes&#39;);
var statusIter=document.getElementById(&#39;statusIter&#39;);
var statusTime=document.getElementById(&#39;statusTime&#39;);
var hoverInfo=document.getElementById(&#39;hoverInfo&#39;);
var timer=null;
function hslToRgb(h,s,l){
h=((h%360)+360)%360; s/=100; l/=100;
var k=function(n){return (n+h/30)%12;};
var a=s*Math.min(l,1-l);
var f=function(n){return l-a*Math.max(-1,Math.min(k(n)-3,Math.min(9-k(n),1)));};
return [Math.round(f(0)*255),Math.round(f(8)*255),Math.round(f(4)*255)];
}
function currentC(){
return {re:parseFloat(reSlider.value), im:parseFloat(imSlider.value)};
}
function currentRes(){ return Math.min(2000, Math.max(128, parseInt(resInput.value)||800)); }
function currentIter(){ return parseInt(iterInput.value)||180; }
function render(){
var c=currentC(), res=currentRes(), maxIter=currentIter();
var t0=performance.now();
cv.width=res; cv.height=res;
var img=ctx.createImageData(res,res);
var data=img.data;
var step=(YMAX-YMIN)/res;
var o=0;
for(var py=0; py<res; py++){
var y=YMAX-(py+0.5)*step;
for(var px=0; px<res; px++){
var x=XMIN+(px+0.5)*step;
var zx=x, zy=y, i=0, zx2=0, zy2=0;
while(i<maxIter){
zx2=zx*zx; zy2=zy*zy;
if(zx2+zy2>4) break;
zy=2*zx*zy+c.im;
zx=zx2-zy2+c.re;
i++;
}
if(i>=maxIter){
data[o++]=6; data[o++]=10; data[o++]=26; data[o++]=255;
}else{
var mag=Math.sqrt(zx2+zy2);
var nu=Math.log(Math.log(mag)/Math.LN2)/Math.LN2;
var sm=i+1-nu;
var hue=((sm*52)+200)%360;
var rgb=hslToRgb(hue,95,62-Math.min(36,sm*1.4));
data[o++]=rgb[0]; data[o++]=rgb[1]; data[o++]=rgb[2]; data[o++]=255;
}
}
}
ctx.putImageData(img,0,0);
var ms=(performance.now()-t0).toFixed(1);
statusTime.textCOntent=ms+&#39; ms&#39;;
statusC.textCOntent=c.re.toFixed(3)+&#39; + &#39;+c.im.toFixed(3)+&#39;i&#39;;
statusRes.textCOntent=res+&#39;×&#39;+res;
statusIter.textCOntent=maxIter;
}
function schedule(){
if(timer) clearTimeout(timer);
timer=setTimeout(function(){
render();
syncLabels();
},90);
}
function syncLabels(){
reValEl.textCOntent=(+reSlider.value).toFixed(3);
imValEl.textCOntent=(+imSlider.value).toFixed(3);
resValEl.textCOntent=currentRes();
iterValEl.textCOntent=currentIter();
}
reSlider.addEventListener(&#39;input&#39;,function(){ reValEl.textCOntent=(+reSlider.value).toFixed(3); schedule(); });
imSlider.addEventListener(&#39;input&#39;,function(){ imValEl.textCOntent=(+imSlider.value).toFixed(3); schedule(); });
iterInput.addEventListener(&#39;input&#39;,function(){ iterValEl.textCOntent=iterInput.value; schedule(); });
resInput.addEventListener(&#39;input&#39;,function(){ resValEl.textCOntent=currentRes(); });
resInput.addEventListener(&#39;change&#39;,render);
var presets=document.querySelectorAll(&#39;.presets span&#39;);
presets.forEach(function(p){
p.addEventListener(&#39;click&#39;,function(){
reSlider.value=p.getAttribute(&#39;data-re&#39;);
imSlider.value=p.getAttribute(&#39;data-im&#39;);
syncLabels();
render();
});
});
cv.addEventListener(&#39;mousemove&#39;,function(e){
var rect=cv.getBoundingClientRect();
var rx=(e.clientX-rect.left)*(cv.width/rect.width);
var ry=(e.clientY-rect.top)*(cv.height/rect.height);
var x=XMIN+(rx+0.5)*( (XMAX-XMIN)/cv.width );
var y=YMAX-(ry+0.5)*( (YMAX-YMIN)/cv.height );
var c=currentC(), maxIter=currentIter();
var zx=x, zy=y, i=0;
while(i<maxIter){
var zx2=zx*zx, zy2=zy*zy;
if(zx2+zy2>4) break;
zy=2*zx*zy+c.im;
zx=zx2-zy2+c.re;
i++;
}
hoverInfo.textCOntent=&#39;复坐标 &#39;+x.toFixed(4)+(y>=0?&#39; + &#39;:&#39; - &#39;)+Math.abs(y).toFixed(4)+&#39;i · 逃逸迭代 &#39;+i+(i>=maxIter?&#39;(集合内)&#39;:&#39;&#39;);
});
var qs=new URLSearchParams(window.location.search);
var qre=parseFloat(qs.get(&#39;re&#39;)), qim=parseFloat(qs.get(&#39;im&#39;));
if(isFinite(qre)&&qre>=-2&&qre<=2) reSlider.value=qre;
if(isFinite(qim)&&qim>=-2&&qim<=2) imSlider.value=qim;
syncLabels();
render();
})();
</script>
</body>
</html>