add fractal page from old site

This commit is contained in:
Crispy 2021-06-26 21:49:40 +02:00
parent a1b500236f
commit c973cb1aec
7 changed files with 417 additions and 19 deletions

303
docs/fractals/fractals.js Normal file
View file

@ -0,0 +1,303 @@
'use strict'
const gpu = new GPU();
class FractalTree {
constructor(id, iterations, mod) {
this.app = document.getElementById(id);
this.canvas = this.app.getElementsByTagName("canvas")[0];
this.canvas.width = 512;
this.canvas.height = 448;
this.ctx = this.canvas.getContext("2d");
this.iterations = iterations;
this.mod = mod;
this.angle = Math.PI * 0.2;
this.update = true;
this.palette = ["#430", "#440", "#450", "#460", "#470", "#480", "#080"];
this.canvas.addEventListener("mousemove", this.mouseMove.bind(this));
this.canvas.addEventListener("mousedown", this.click.bind(this));
}
static vector(l, angle) {
return {
x: Math.cos(angle) * l,
y: Math.sin(angle) * l
};
}
tree(x, y, length, i, angle) {
if (i==0) { return; }
let dir = FractalTree.vector(length * this.mod, angle + this.angle);
this.ctx.beginPath();
this.ctx.moveTo(x, y);
this.ctx.lineWidth = i;
this.ctx.strokeStyle = this.palette[this.iterations-i];
this.ctx.lineTo(x + dir.x, y - dir.y);
this.ctx.stroke();
this.tree(x + dir.x, y - dir.y, length*this.mod, i-1, angle - this.angle);
this.tree(x + dir.x, y - dir.y, length*this.mod, i-1, angle + this.angle);
}
render() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.tree(256, this.canvas.height-64, 128, this.iterations, Math.PI/2 - this.angle);
}
mouseMove(event) {
if (this.update) {
let x = event.clientX - this.canvas.getBoundingClientRect().left;
this.angle = x * Math.PI / this.canvas.width;
this.render();
}
}
click(event) {
this.update = !this.update;
if (this.update) {
let x = event.clientX - this.canvas.getBoundingClientRect().left;
this.angle = x * Math.PI / this.canvas.width;
this.render();
}
}
setIter(i) {
this.iterations = i;
this.render();
}
setMod(m) {
this.mod = m;
this.render();
}
}
class Mandelbrot {
constructor(id, iter=255, width=512, height=512, minX=-2, minY=-1.5, maxX=1, maxY=1.5) {
this.app = document.getElementById(id);
this.canvas = this.app.getElementsByTagName("canvas")[0];
this.canvas.width = width;
this.canvas.height = height;
this.ctx = this.canvas.getContext("2d");
this.renderBtn = this.app.getElementsByClassName("controlbar")[0].getElementsByTagName("button")[0];
this.renderBtn2 = this.app.getElementsByClassName("controlbar")[0].getElementsByTagName("button")[1];
this.init(minX, minY, maxX, maxY);
this.defaultZoom = [minX, minY, maxX, maxY];
this.iter = iter;
this.palette = [16, 32, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232, 240, 248];
this.canvas.addEventListener("mousedown", this.zoom.bind(this));
}
zoom(event) {
//zoom function
let zoomf = 8;
let x = this.reScaleX(event.clientX - this.canvas.getBoundingClientRect().left);
let y = this.reScaleY(event.clientY - this.canvas.getBoundingClientRect().top);
let dx = (this.maxX - this.minX)/zoomf;
let dy = (this.maxY - this.minY)/zoomf;
this.init(x - dx, y - dy, x + dx, y + dy);
this.render();
}
reset() {
this.init(this.defaultZoom[0], this.defaultZoom[1], this.defaultZoom[2], this.defaultZoom[3]);
this.render();
}
setIter(x) {
this.iter = x;
this.render();
}
init(minX, minY, maxX, maxY) {
this.minX = minX;
this.minY = minY;
this.maxX = maxX;
this.maxY = maxY;
this.scaleX = (maxX - minX) / this.canvas.width;
this.scaleY = (maxY - minY) / this.canvas.height;
}
reScaleX(x) {
return x * this.scaleX + this.minX;
}
reScaleY(y) {
return y * this.scaleY + this.minY;
}
point(x0, y0) {
let x = 0, y = 0;
let i = 0;
let x2 = 0, y2 = 0;
while (x2 + y2 <= 4 && i < this.iter) {
y = 2*x*y + y0;
x = x2 - y2 + x0;
x2 = x*x;
y2 = y*y;
i++;
}
return i;
}
render() {
let start = new Date();
let result = this.ctx.getImageData(0,0, this.canvas.width, this.canvas.height);
let px = 0;
let yp;
for (let yPos = 0; yPos < this.canvas.height; yPos++) {
yp = this.reScaleY(yPos);
for (let xPos = 0; xPos < this.canvas.width; xPos++) {
let i = this.point(this.reScaleX(xPos), yp);
if (i != this.iter) {
let col = this.palette[Math.min(i, this.palette.length-1)]
result.data[px] = 0;
result.data[px+1] = col;
result.data[px+2] = col;
} else {
result.data[px] = 0;
result.data[px+1] = 0;
result.data[px+2] = 0;
}
result.data[px+3] = 255;
px += 4;
}
}
this.ctx.putImageData(result, 0, 0);
this.renderBtn.textContent = `Reset ${new Date() - start}ms`;
}
gpuRender() {
let start = new Date();
let kernel = gpu.createKernel(function(scaleX, scaleY, minX, minY, iter) {
let x0 = this.thread.x * scaleX + minX;
let y0 = this.thread.y * scaleY + minY;
let x = 0, y = 0;
let i = 0;
let x2 = 0, y2 = 0;
while (x2 + y2 < 4 && i < iter) {
y = 2*x*y + y0;
x = x2 - y2 + x0;
x2 = x*x;
y2 = y*y;
i++;
}
if (i != iter) {
this.color(0, i/iter, i/iter, 1);
this.color(0, i/255, i/255, 1);//i is 0?
this.color(this.thread.x/512, this.thread.y/512, i/255);
} else {
this.color(1, 0, 0, 1);
}
//this.color(this.thread.x/512, this.thread.y/512, i/256);
//this.color(x0, y0, 0, 1)
},
{output:[512, 512], graphical:true, loopMaxIterations: this.iter});
kernel(this.scaleX, this.scaleY, this.minX, this.minY, this.iter);
//let kernel = gpu.createKernel(function() {this.color(0, 0, 1);}).setOutput([512, 512]).setGraphical(true);
//kernel();
let result = kernel.getPixels();
this.ctx.putImageData(new ImageData(result, 512, 512), 0, 0);
this.renderBtn.textContent = `Reset ${new Date() - start}ms`;
}
}
class Multibrot extends Mandelbrot {
constructor(id, power, iter=255, width=512, height=512, minX=-2, minY=-2, maxX=2, maxY=2) {
super(id, iter, width, height, minX, minY, maxX, maxY);
this.power = power;
}
point(x0, y0) {
let x = 0, y = 0;
let i = 0;
let xtmp, xxyyn, atn;
let n2 = this.power/2;
while (x*x + y*y <= 4 && i < this.iter) {
xxyyn = (x*x+y*y)**(n2);
atn = this.power*Math.atan2(y, x);
xtmp = xxyyn * Math.cos(atn) + x0;
y = xxyyn * Math.sin(atn) + y0;
x = xtmp;
i++;
}
return i;
}
setPower(x) {
this.power = x;
this.render();
}
}
class Julia extends Mandelbrot {
constructor(id, iter=255, width=512, height=512, minX=-2, minY=-2, maxX=2, maxY=2) {
super(id, iter, width, height, minX, minY, maxX, maxY);
this.cx = this.reScaleX(width/2);
this.cy = this.reScaleY(height/3.2);
this.update = true;
this.canvas.removeEventListener("mousedown", this.zoom);
this.canvas.addEventListener("mousedown", this.click.bind(this));
this.canvas.addEventListener("mousemove", this.mouseMove.bind(this));
}
click(event) {
this.update = !this.update;
this.mouseMove(event);
}
zoom() {
return;
}
mouseMove(event) {
if (this.update) {
this.cx = this.reScaleX(event.clientX - this.canvas.getBoundingClientRect().left);
this.cy = this.reScaleY(event.clientY - this.canvas.getBoundingClientRect().top);
this.render();
}
}
point(zx, zy) {
let i = 0, xtmp = 0;
let zx2 = zx*zx, zy2 = zy*zy;
while (zx2 + zy2 < 4 && i < this.iter) {
xtmp = zx2 - zy2;
zy = 2*zx*zy + this.cy;
zx = xtmp + this.cx;
zx2 = zx*zx;
zy2 = zy*zy;
i++;
}
return i;
}
}
let fractalTree = new FractalTree("fractal-tree", 12, 0.75);
let mandelbrot = new Mandelbrot("mandelbrot");
let multibrot = new Multibrot("multibrot", 4);
let juliaSet = new Julia("julia-set", 64, 512, 512);
fractalTree.render();
mandelbrot.render();
juliaSet.render();

View file

@ -22,7 +22,47 @@
</nav> </nav>
<main> <main>
<h1>Fractals</h1> <h1>Fractals</h1>
<p>this is real content i promise</p> <h2>Fractal tree</h2>
<p>This is a fractal tree.</p>
<p>The tree splits into two parts, with an angle defined by the cursor's x positon. The number of iterations is defined by the first input field (which defaults to 12). Each branch is slightly smaller than its parent, as defined by the second input field. Click the canvas to freeze the image at any moment.</p>
<div class="demo-render" id="fractal-tree">
<canvas></canvas>
<div class="controlbar">
<input type="number" min=6 max=15 value=12 onchange="fractalTree.setIter(value)">
<input type="number" min=0.65 max=1 step=0.025 value=0.75 onchange="fractalTree.setMod(value)">
</div>
</div>
<h2>Mandelbrot</h2>
<p>The mandelbrot set is defined as the set of complex numbers for which a specific function (<i>F<sub>c</sub>(z) = z<sup>2</sup> + c</i>) stays within distance 2 from the origin when iterated from z=0.</p>
<div class="demo-render" id="mandelbrot">
<canvas></canvas>
<div class="controlbar">
<button type="button" onclick="mandelbrot.reset()">Reset</button>
<button type="button" onclick="mandelbrot.gpuRender()">GPU</button>
<input type="number" min=1 max=1000 value=256 onchange="mandelbrot.setIter(value)">
</div>
</div>
<h2>Multibrot set</h2>
<p>A multibrot set is a variant of the mandelbrot set where the functions exponent can be anything. If the exponent (third input field) is 2, you get the regular mandelbrot set.</p>
<div class="demo-render" id="multibrot">
<canvas></canvas>
<div class="controlbar">
<button type="button" onclick="multibrot.reset()">Reset</button>
<input type="number" min=1 max=1000 value=256 onchange="multibrot.setIter(value)">
<input type="number" min=0 max=32 step=0.1 value=4 onchange="multibrot.setPower(value)">
</div>
</div>
<h2>Julia set</h2>
<p>The julia set is similar to the mandelbrot set.</p>
<div class="demo-render" id="julia-set">
<canvas></canvas>
<div class="controlbar">
<button type="button" onclick="juliaSet.reset()">Reset</button>
<input type="number" min=8 max=1000 value=80 step=8 onchange="juliaSet.setIter(value)">
</div>
</div>
<script src="/libraries/gpu-browser.min.js"></script>
<script src="fractals.js"></script>
</main> </main>
<footer> <footer>
<p>crispypin.cc</p> <p>crispypin.cc</p>

14
docs/libraries/gpu-browser.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -52,17 +52,22 @@ header h1 {
footer { footer {
grid-column: 1 / -1; grid-column: 1 / -1;
margin: 25px; margin-top: 5px;
margin-bottom: 10px;
text-align: center; text-align: center;
} }
footer p {
margin: 5px;
}
main { main {
padding: 0 20px; padding: 0 20px;
grid-column: 2 / -2; grid-column: 2 / -2;
background-color: #282828; background-color: #282828;
} }
.render { .demo-render {
margin: 20px; margin: 20px;
width: -webkit-min-content; width: -webkit-min-content;
width: -moz-min-content; width: -moz-min-content;
@ -148,6 +153,7 @@ main {
} }
.clickable, nav li, .controlbar button, .controlbar input, .scroll-reset { .clickable, nav li, .controlbar button, .controlbar input, .scroll-reset {
border-radius: 4px;
background-color: #4a4; background-color: #4a4;
} }
@ -172,12 +178,7 @@ main {
bottom: 20px; bottom: 20px;
width: 40px; width: 40px;
height: 40px; height: 40px;
border-radius: 25%;
background-image: url("uparrow.png"); background-image: url("uparrow.png");
cursor: pointer; cursor: pointer;
} }
.img-right {
float: right;
}
/*# sourceMappingURL=style.css.map */ /*# sourceMappingURL=style.css.map */

View file

@ -1,6 +1,6 @@
{ {
"version": 3, "version": 3,
"mappings": "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", "mappings": "AAWA,AAAA,IAAI,CAAC;EACD,WAAW,EAAE,8CAA8C;EAC3D,gBAAgB,EARV,OAAO;EASb,KAAK,EANI,IAAI;EAQb,OAAO,EAAE,IAAI;EACb,kBAAkB,EAAE,kBAAkB;EAEtC,qBAAqB,EAAE,aAAa;EAEpC,MAAM,EAAE,CAAC;EACT,UAAU,EAAE,KAAK;CAEpB;;AAED,AAAA,GAAG,CAAC;EACA,WAAW,EAAE,MAAM;CAoBtB;;AArBD,AAEI,GAFD,CAEC,EAAE,CAAC;EACC,eAAe,EAAE,IAAI;EACrB,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,IAAI;EACb,OAAO,EAAE,QAAQ;EACjB,QAAQ,EAAE,GAAG;EACb,qBAAqB,EAAE,sCAAsC;CAChE;;AATL,AAUI,GAVD,CAUC,EAAE,CAAC;EAEC,OAAO,EAAE,GAAG;CACf;;AAbL,AAcI,GAdD,CAcC,CAAC,CAAC;EACE,SAAS,EAAE,IAAI;EACf,KAAK,EAAE,IAAI;EACX,eAAe,EAAE,IAAI;EACrB,OAAO,EAAE,KAAK;EACd,UAAU,EAAE,MAAM;CACrB;;AAGL,AAAA,MAAM,CAAC;EACH,WAAW,EAAE,MAAM;EACnB,gBAAgB,EA9CV,OAAO;EA+Cb,OAAO,EAAE,CAAC;CAKb;;AARD,AAII,MAJE,CAIF,EAAE,CAAC;EACC,SAAS,EAAE,IAAI;EACf,MAAM,EAAE,CAAC;CACZ;;AAGL,AAAA,MAAM,CAAC;EACH,WAAW,EAAE,MAAM;EACnB,UAAU,EAAE,GAAG;EACf,aAAa,EAAE,IAAI;EACnB,UAAU,EAAE,MAAM;CAIrB;;AARD,AAKI,MALE,CAKF,CAAC,CAAC;EACE,MAAM,EAAE,GAAG;CACd;;AAGL,AAAA,IAAI,CAAC;EACD,OAAO,EAAE,MAAM;EACf,WAAW,EAAE,MAAM;EACnB,gBAAgB,EAlEL,OAAO;CAmErB;;AAED,AAAA,YAAY,CAAC;EACT,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,WAAW;EAClB,gBAAgB,EAAE,IAAI;CACzB;;AAED,AAAA,WAAW,CAAC;EACR,gBAAgB,EA7EV,OAAO;EA8Eb,OAAO,EAAE,OAAO;EAChB,MAAM,EAAE,WAAW;EACnB,OAAO,EAAE,IAAI;EAEb,eAAe,EAAE,YAAY;EAC7B,aAAa,EAAE,OAAO;EACtB,SAAS,EAAE,IAAI;CAuDlB;;AA/DD,AAUI,WAVO,CAUP,MAAM,EAVV,WAAW,CAUC,KAAK,CAAC;EAEV,OAAO,EAAE,OAAO;EAChB,MAAM,EAAE,IAAI;EACZ,MAAM,EAAE,cAAc;EACtB,MAAM,EAAE,CAAC;EACT,MAAM,EAAE,OAAO;EAEf,SAAS,EAAE,CAAC;EACZ,MAAM,EAAE,GAAG;CACd;;AApBL,AAqBI,WArBO,CAqBP,OAAO,CAAC;EACJ,kBAAkB,EAAE,IAAI;EACxB,eAAe,EAAE,IAAI;EACrB,OAAO,EAAE,IAAI;EACb,aAAa,EAAE,CAAC;EAChB,MAAM,EAAE,IAAI;EACZ,OAAO,EAAE,CAAC;EACV,MAAM,EAAE,GAAG;EACX,MAAM,EAAE,OAAO;CAwBlB;;AArDL,AA+BQ,WA/BG,CAqBP,OAAO,AAUF,sBAAsB,CAAC;EACpB,kBAAkB,EAAE,IAAI;EACxB,UAAU,EAAE,IAAI;EAChB,aAAa,EAAE,GAAG;EAClB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,gBAAgB,EAnHT,IAAI;EAoHX,MAAM,EAAE,CAAC;EACT,aAAa,EAAE,CAAC;EAChB,MAAM,EAAE,cAAc;CACzB;;AAzCT,AA0CQ,WA1CG,CAqBP,OAAO,AAqBF,kBAAkB,CAAC;EAChB,6CAA6C;EAC7C,eAAe,EAAE,IAAI;EACrB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,gBAAgB,EA7HT,IAAI;EA8HX,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;EACV,aAAa,EAAE,CAAC;EAChB,MAAM,EAAE,cAAc;CACzB;;AApDT,AAsDI,WAtDO,CAsDP,KAAK,CAAC;EACF,gBAAgB,EAnId,OAAO;EAoIT,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,GAAG;EACX,WAAW,EAAE,6CAA6C;CAC7D;;AA3DL,AA4DI,WA5DO,CA4DP,YAAY,CAAC;EACT,UAAU,EAAE,GAAG;CAClB;;AAGL,AAAA,UAAU,EAxHV,GAAG,CAUC,EAAE,EA6CN,WAAW,CAUP,MAAM,EAVV,WAAW,CAUC,KAAK,EAwEjB,aAAa,CAjBF;EACP,aAAa,EAAE,GAAG;EAClB,gBAAgB,EApJR,IAAI;CAiKf;;AAfD,AAGI,UAHM,AAGL,MAAM,EA3HX,GAAG,CAUC,EAAE,AAiHD,MAAM,EApEX,WAAW,CAUP,MAAM,AA0DL,MAAM,EApEX,WAAW,CAUC,KAAK,AA0DZ,MAAM,EAcX,aAAa,AAdR,MAAM,CAAC;EACJ,gBAAgB,EApJN,IAAI;CAqJjB;;AALL,AAMI,UANM,AAML,OAAO,EA9HZ,GAAG,CAUC,EAAE,AAoHD,OAAO,EAvEZ,WAAW,CAUP,MAAM,AA6DL,OAAO,EAvEZ,WAAW,CAUC,KAAK,AA6DZ,OAAO,EAWZ,aAAa,AAXR,OAAO,CAAC;EACL,gBAAgB,EAtJL,IAAI;CAuJlB;;AARL,AASI,UATM,AASL,SAAS,EAjId,GAAG,CAUC,EAAE,AAuHD,SAAS,EA1Ed,WAAW,CAUP,MAAM,AAgEL,SAAS,EA1Ed,WAAW,CAUC,KAAK,AAgEZ,SAAS,EAQd,aAAa,AARR,SAAS,CAAC;EACP,gBAAgB,EAxJH,IAAI;EAyJjB,eAAe,EAAE,YAAY;EAC7B,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,OAAO;CAClB;;AAGL,AAAA,aAAa,CAAC;EAEV,QAAQ,EAAE,KAAK;EACf,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,gBAAgB,EAAE,kBAAkB;EACpC,MAAM,EAAE,OAAO;CAClB",
"sources": [ "sources": [
"style.scss" "style.scss"
], ],

View file

@ -59,8 +59,12 @@ header {
footer { footer {
grid-column: 1 / -1; grid-column: 1 / -1;
margin: 25px; margin-top: 5px;
margin-bottom: 10px;
text-align: center; text-align: center;
p {
margin: 5px;
}
} }
main { main {
@ -69,7 +73,7 @@ main {
background-color: $main-page-bg; background-color: $main-page-bg;
} }
.render { .demo-render {
margin: 20px; margin: 20px;
width: min-content; width: min-content;
background-color: #000; background-color: #000;
@ -84,7 +88,7 @@ main {
justify-content: space-evenly; justify-content: space-evenly;
align-content: stretch; align-content: stretch;
flex-wrap: wrap; flex-wrap: wrap;
button, input { button, input {
@extend .clickable; @extend .clickable;
padding: 4px 6px; padding: 4px 6px;
@ -105,7 +109,7 @@ main {
padding: 0; padding: 0;
margin: 2px; margin: 2px;
cursor: pointer; cursor: pointer;
&::-webkit-slider-thumb { &::-webkit-slider-thumb {
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
@ -141,6 +145,7 @@ main {
} }
.clickable { .clickable {
border-radius: 4px;
background-color: $main-item; background-color: $main-item;
&:hover { &:hover {
background-color: $main-item-hover; background-color: $main-item-hover;
@ -163,11 +168,6 @@ main {
bottom: 20px; bottom: 20px;
width: 40px; width: 40px;
height: 40px; height: 40px;
border-radius: 25%;
background-image: url("uparrow.png"); background-image: url("uparrow.png");
cursor: pointer; cursor: pointer;
} }
.img-right {
float: right;
}

View file

@ -11,7 +11,47 @@
<include header.html/> <include header.html/>
<main> <main>
<h1>Fractals</h1> <h1>Fractals</h1>
<p>this is real content i promise</p> <h2>Fractal tree</h2>
<p>This is a fractal tree.</p>
<p>The tree splits into two parts, with an angle defined by the cursor's x positon. The number of iterations is defined by the first input field (which defaults to 12). Each branch is slightly smaller than its parent, as defined by the second input field. Click the canvas to freeze the image at any moment.</p>
<div class="demo-render" id="fractal-tree">
<canvas></canvas>
<div class="controlbar">
<input type="number" min=6 max=15 value=12 onchange="fractalTree.setIter(value)">
<input type="number" min=0.65 max=1 step=0.025 value=0.75 onchange="fractalTree.setMod(value)">
</div>
</div>
<h2>Mandelbrot</h2>
<p>The mandelbrot set is defined as the set of complex numbers for which a specific function (<i>F<sub>c</sub>(z) = z<sup>2</sup> + c</i>) stays within distance 2 from the origin when iterated from z=0.</p>
<div class="demo-render" id="mandelbrot">
<canvas></canvas>
<div class="controlbar">
<button type="button" onclick="mandelbrot.reset()">Reset</button>
<button type="button" onclick="mandelbrot.gpuRender()">GPU</button>
<input type="number" min=1 max=1000 value=256 onchange="mandelbrot.setIter(value)">
</div>
</div>
<h2>Multibrot set</h2>
<p>A multibrot set is a variant of the mandelbrot set where the functions exponent can be anything. If the exponent (third input field) is 2, you get the regular mandelbrot set.</p>
<div class="demo-render" id="multibrot">
<canvas></canvas>
<div class="controlbar">
<button type="button" onclick="multibrot.reset()">Reset</button>
<input type="number" min=1 max=1000 value=256 onchange="multibrot.setIter(value)">
<input type="number" min=0 max=32 step=0.1 value=4 onchange="multibrot.setPower(value)">
</div>
</div>
<h2>Julia set</h2>
<p>The julia set is similar to the mandelbrot set.</p>
<div class="demo-render" id="julia-set">
<canvas></canvas>
<div class="controlbar">
<button type="button" onclick="juliaSet.reset()">Reset</button>
<input type="number" min=8 max=1000 value=80 step=8 onchange="juliaSet.setIter(value)">
</div>
</div>
<script src="/libraries/gpu-browser.min.js"></script>
<script src="fractals.js"></script>
</main> </main>
<include footer.html/> <include footer.html/>
</body> </body>