spout: s17

This commit is contained in:
mehbark 2026-03-29 23:42:32 -04:00
parent c63127f123
commit 9dfc176978
Signed by: mbk
GPG key ID: E333EC1335FFCCDB

View file

@ -82,19 +82,80 @@ h2 {
window.onhashchange = hl_ref;
Number.prototype.map = function(a,b,c,d){return c+(d-c)*((this-a)/(b-a))};
/**
* @type (s: number, ids: string) => Element[]
*/
let elems = (s, ids) => ids.split(" ").map(i => document.getElementById(`s${s}-${i}`));
window.onload = () => {
hl_ref();
let [s9lhs, s9rhs] = elems(9, "lhs rhs");
const params = new URLSearchParams(window.location.search);
params.get("s9-lhs") && (s9lhs.value = params.get("s9-lhs"));
params.get("s9-rhs") && (s9rhs.value = params.get("s9-rhs"));
s17();
};
function s17() {
let [canvas, lhs, rhs, button] = elems(17, "canvas lhs rhs button");
const params = new URLSearchParams(window.location.search);
params.get("s17-lhs") && (lhs.value = params.get("s17-lhs"));
params.get("s17-rhs") && (rhs.value = params.get("s17-rhs"));
/**
* @type CanvasRenderingContext2D
*/
let ctx = canvas.getContext("2d");
let width = ctx.canvas.width;
let height = ctx.canvas.height;
ctx.fillStyle = "#76a6e4";
const update = () => {
ctx.clearRect(0, 0, width, height);
const f = eval(`(x, y) => {with (Math) {return (${lhs.value}) - (${rhs.value})}}`);
for (let x = 0; x < width; x++) {
for (let y = 0; y < width; y++) {
let pos_count = 0;
for (const dx of [-0.5, 0.5]) {
for (const dy of [-0.5, 0.5]) {
const diff = f((x + dx).map(0, width, -4, 4), (y + dy).map(0, height, 4, -4));
diff > 0 && pos_count++;
}
}
if (pos_count == 1 || pos_count == 2) {
ctx.fillRect(x, y, 1, 1);
}
}
}
};
button.onclick = update;
update();
}
</script>
</head>
<body>
<h1 style="margin: 1rem">spout: reverse-chron html pieces by <a href="https://terezi.pyrope.net">mehbark</a></h1>
<article id="s17">
<h1><a href="#s17">#</a> graphing with sign-changes</h1>
<p>I had somehow never heard of this canonical graphing technique until watching <a href="https://www.youtube.com/watch?v=YJJk0iLJ4Ks">this video about a 3d graphing calculator in minecraft</a></p>
<p>just look at the signs of the difference between the left and right sides of the equation at four points for each pixel. then fill the pixel if not every sample has the same sign</p>
<canvas id="s17-canvas" width="512" height="512"></canvas>
<input id="s17-lhs" type="text" value="y" />
<span>=</span>
<input id="s17-rhs" type="text" value="sin(x**2)" />
<input id="s17-button" type="button" value="graph!">
</article>
<article id="s16">
<h1><a href="#s16">#</a> binary search over the integers (todo)</h1>
@ -170,7 +231,7 @@ h2 {
background-position: 2cm -0.3cm;
background-repeat: no-repeat;
color: #2c2c2c;
//padding: 0.5cm 1cm;
/* padding: 0.5cm 1cm; */
font-family: "Charter", charter, serif;
outline: 0.2cm solid black;
filter: blur(0.25px);
@ -238,6 +299,7 @@ fair warning: especially with larger batch sizes, this is liable to freeze up th
<pre id=s12-output style="overflow: auto; height: 36ch; width: 100%; word-break: break-all; white-space: pre-wrap;">
3.</pre>
<button onclick='
(() => {
if (this.interval) {
clearInterval(this.interval);
this.interval = null;
@ -277,6 +339,7 @@ this.interval = setInterval(() => {
digits.innerText = digs;
}
}, 0);
})();
'>sπgot!</button> <span id=s12-digits style="font-family: monospace">1</span> digits in batches of <input id=s12-batch type=number min=1 max=100000 value=10></input> <p style="color: red" id=s12-error></span>
<p>gotta say, it's really sweet working with native generators. not really necessary here, but elegant.
bigints were the real hero, i almost discarded the idea before i remembered js had them <span class=emoticon>:P</span>
@ -290,6 +353,7 @@ bigints were the real hero, i almost discarded the idea before i remembered js h
i hope i can do it!
<canvas id="s11-canvas" width=300 height=300></canvas><br>
<input type=range id="s11-slider" min=0 max=12 value=0 onchange='
(() => {
let [canvas, slider, best] = elems(11, "canvas slider best");
let ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, 4113, 4113);
@ -315,6 +379,7 @@ for (let i = steps; i >= 1; i--) {
}
}
best.innerText = inside * 4;
})();
'/> best guess: <span id="s11-best">idk</span>
<p>i did it! not super efficiently, but it was fun. the slider goes up to 12, which is <em>really</em> pushing it, so exercise caution
</article>
@ -326,6 +391,7 @@ best.innerText = inside * 4;
and i'd like to implement my favorite approach here</p>
<canvas id="s10-canvas" width=314 height=314></canvas><br>
<input id="s10-samples" type="number" min=1 value=1000> in batches of <input id="s10-batch" type="number" min=1 value=10> <button onclick='
(() => {
let [canvas, samples, inside, total, best, batch] = elems(10, "canvas samples inside total best batch");
let n = +samples.value;
let b = +batch.value;
@ -354,6 +420,7 @@ setTimeout(function sample() {
best.innerText = 4 * ins/tot;
if (n > 0) setTimeout(sample, 0);
}, 0);
})();
'>sample!</button><br>
<p>current best guess: <span id="s10-inside">0</span>/<span id="s10-total">0</span> * 4 = <span id="s10-best">idk</span>
<p>this is thoroughly ingrained in my brain, but i hope it's still fairly intuitive for others.
@ -367,6 +434,7 @@ i like how the boundary becomes more clear with more samples, it makes the accur
that might be here! in ! th efuture</p>
<canvas id="s9-canvas" width=300 height=300></canvas><br>
<input id="s9-lhs" value="x*x + y*y"> = <input id="s9-rhs" value="1"> <button onclick='
(() => {
if (this.innerText == "stop D:") {
clearInterval(this.interval);
this.innerText = "graph!";
@ -413,6 +481,7 @@ that might be here! in ! th efuture</p>
// the stop button works now, so why limit steps?
let steps = 1/0;
this.interval = setInterval(function loop() {step(); draw(); if (steps-- <= 0) clearInterval(this.interval)}, 0)
})();
'>graph!</button> <input type=number id=s9-samples value=100></input> samples<sup>2</sup>
<p>okay dang this looks freaking great. hue is based on angle, look at the code! i love this
<p>i have decided that instead of making it more accurate, i will leave it at this place of looking very cool
@ -445,6 +514,7 @@ that might be here! in ! th efuture</p>
<div class="controls"><button id="s8-l"></button><button id="s8-u"></button><button id="s8-d"></button><button id="s8-r"></button></div>
<div>winning? <span id="s8-winning">no.</span> moves? <span id="s8-moves"></span></div>
<script>
(() => {
let [input, l, u, d, r, winning, moves] = elems(8, "input l u d r winning moves");
let step = (dx, dy, c) => () => {
let puzzle = input.value.split("\n");
@ -519,16 +589,18 @@ that might be here! in ! th efuture</p>
u.onclick = step( 0, -1, "u");
d.onclick = step( 0, 1, "d");
r.onclick = step( 1, 0, "r");
})();
</script>
</article>
<article id="s7">
<h1><a href="#s7">#</a> i may be stupid</h1>
<p>i realized something when talking about <a href="#s7">s7</a>: i may be stupid.
first of all, it's worth understanding that <a href="#s7">s7</a> is actually my third go at this technique,
<p>i realized something when talking about <a href="#s6">s6</a>: i may be stupid.
first of all, it's worth understanding that <a href="#s6">s6</a> is actually my third go at this technique,
the first time was on <code>about:blank</code> in canvas, and the second time was in <a href="https://www.lexaloffle.com/picotron.php">picotron</a>.</p>
<canvas id="s7-canvas" width=300 height=300></canvas><br>
<input id="s7-input" value="sin(x)"> <button id="s7-graph" onclick='
(() => {
let ctx = document.getElementById("s7-canvas").getContext("2d");
ctx.fillStyle = "#76a6e4";
@ -542,6 +614,7 @@ the first time was on <code>about:blank</code> in canvas, and the second time wa
for (let x = x0; x <= x1; x += (x1 - x0)/1200) {
ctx.fillRect(x.map(x0, x1, 0, 300), f(x).map(y0, y1, 300, 0), 1, 1);
};
})();
'>graph!</button> <button id="s7-deriv" onclick='
this.innerText++;
let n = +this.innerText;