summary refs log tree commit diff
path: root/www/causal.agency
diff options
context:
space:
mode:
Diffstat (limited to 'www/causal.agency')
-rw-r--r--www/causal.agency/.gitignore4
-rw-r--r--www/causal.agency/Makefile23
-rw-r--r--www/causal.agency/alpha.html92
-rw-r--r--www/causal.agency/index.776
-rw-r--r--www/causal.agency/lands.html176
-rw-r--r--www/causal.agency/style.css28
6 files changed, 399 insertions, 0 deletions
diff --git a/www/causal.agency/.gitignore b/www/causal.agency/.gitignore
new file mode 100644
index 00000000..b00b1c3c
--- /dev/null
+++ b/www/causal.agency/.gitignore
@@ -0,0 +1,4 @@
+index.html
+leveler.html
+scheme.css
+scheme.png
diff --git a/www/causal.agency/Makefile b/www/causal.agency/Makefile
new file mode 100644
index 00000000..8c74f8f1
--- /dev/null
+++ b/www/causal.agency/Makefile
@@ -0,0 +1,23 @@
+WEBROOT = /var/www/causal.agency
+
+GEN = index.html scheme.css scheme.png
+FILES = ${GEN} style.css alpha.html lands.html
+
+all: ${FILES}
+
+.SUFFIXES: .7 .html
+
+.7.html:
+	mandoc -T html -O style=style.css $< > $@
+
+scheme.css:
+	scheme -st > scheme.css
+
+scheme.png:
+	scheme -g > scheme.png
+
+install: ${FILES}
+	install -C -m 644 ${FILES} ${WEBROOT}
+
+clean:
+	rm -f ${GEN}
diff --git a/www/causal.agency/alpha.html b/www/causal.agency/alpha.html
new file mode 100644
index 00000000..0d83f530
--- /dev/null
+++ b/www/causal.agency/alpha.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>all 26 letters of the alphabet RANKED</title>
+<style>
+body, button { font-size: 200%; text-align: center; }
+button { margin: 1em; padding: 1ch; }
+button#shuffle { font-size: 100%; }
+</style>
+
+which letter do you like more?
+<p>
+<button id="a">A</button>
+<button id="b">B</button>
+<p>
+<details>
+<summary>current ranking</summary>
+<p>
+<span id="ranking">ABCDEFGHIJKLMNOPQRSTUVWXYZ</span>
+<p>
+<button id="shuffle">reshuffle</button>
+</details>
+
+<script>
+let buttonA = document.getElementById("a");
+let buttonB = document.getElementById("b");
+let ranking = document.getElementById("ranking");
+
+let alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
+let rand = (bound) => Math.floor(Math.random() * bound);
+function shuffle() {
+	for (let i = alpha.length - 1; i > 0; --i) {
+		let j = rand(i + 1);
+		let x = alpha[i];
+		alpha[i] = alpha[j];
+		alpha[j] = x;
+	}
+}
+if (localStorage.getItem("alpha")) {
+	alpha = localStorage.getItem("alpha").split("");
+} else {
+	shuffle();
+}
+
+let index = 0;
+let even = true;
+function choose(o) {
+	if (o == "b") {
+		let x = alpha[index];
+		alpha[index] = alpha[index + 1];
+		alpha[index + 1] = x;
+	}
+	index += 2;
+	if (index > alpha.length - 2) {
+		even = !even;
+		index = (even ? 0 : 1);
+	}
+	update();
+}
+
+document.onkeydown = function(event) {
+	if (event.key.toUpperCase() == alpha[index]) {
+		choose("a");
+	} else if (event.key.toUpperCase() == alpha[index + 1]) {
+		choose("b");
+	}
+}
+
+function update() {
+	localStorage.setItem("alpha", alpha.join(""));
+	ranking.innerText = alpha.join("");
+	let a = buttonA;
+	let b = buttonB;
+	if (rand(2)) {
+		a = buttonB;
+		b = buttonA;
+	}
+	let lc = (c) => c;
+	if (rand(2)) lc = (c) => c.toLowerCase();
+	a.innerText = lc(alpha[index]);
+	b.innerText = lc(alpha[index + 1]);
+	a.onclick = () => choose("a");
+	b.onclick = () => choose("b");
+}
+update();
+
+document.getElementById("shuffle").onclick = function() {
+	if (confirm("Are you SURE you want to throw away all your hard work?")) {
+		shuffle();
+		update();
+	}
+}
+</script>
diff --git a/www/causal.agency/index.7 b/www/causal.agency/index.7
new file mode 100644
index 00000000..1e019574
--- /dev/null
+++ b/www/causal.agency/index.7
@@ -0,0 +1,76 @@
+.Dd April 18, 2024
+.Dt CAUSAL.AGENCY 7
+.Os "Causal Agency"
+.
+.Sh NAME
+.Nm june
+.Nd computer enthusiast (she/her)
+.
+.Sh SYNOPSIS
+.Nm mail
+.Mt june@causal.agency
+.Nm
+in
+.Li #ascii.town
+on tilde.chat
+.
+.Sh DESCRIPTION
+I make mostly IRC software in C.
+I like
+.Ox
+but also the GPL.
+I just want to read books
+and try to learn to be kinder.
+When I can I'd like to talk to strangers
+and experience more magic.
+.
+.Pp
+.Lk https://git.causal.agency code
+\(em
+.Lk https://text.causal.agency words
+\(em
+.Lk https://photo.causal.agency photos
+\(em
+.Lk /list/ mailist
+.
+.Pp
+These are some things I've done:
+.Bl -tag -width Ds
+.It Lk https://git.causal.agency/pounce/about pounce
+a multi-client-first IRC bouncer
+.It Lk https://git.causal.agency/catgirl/about catgirl
+a cosy IRC client
+.It Lk https://git.causal.agency/litterbox/about litterbox
+a full-text search IRC logger
+.It Lk https://git.causal.agency/scooper/about scooper
+a web interface for litterbox
+.It Lk https://git.causal.agency/kitd/about kitd
+a process supervisor
+.It Lk https://git.causal.agency/imbox/about "imbox & git-fetch-email"
+a tool to pull patches out of IMAP
+.It Lk https://git.causal.agency/bubger/about bubger
+a mailing list archive generator for IMAP
+.It Lk https://git.causal.agency/notemap/about notemap
+a tool to mirror text files to IMAP notes
+.It Lk https://ascii.town/explore.html torus@ascii.town
+a collaborative ASCII art project
+.It Lk ssh://play@ascii.town play@ascii.town
+some games to play over
+.Xr ssh 1
+.It Lk https://git.causal.agency/cards/about cards
+a
+.Pa CARDS.DLL
+loader for SDL
+.It Lk scheme.png scheme
+an earthy terminal colour scheme
+.El
+.
+.Sh SEE ALSO
+.Bl -bullet
+.It
+.Lk /bin/ bin
+.It
+.Lk lands.html "Magic lands quiz"
+.It
+.Lk alpha.html "alphabet ranking game"
+.El
diff --git a/www/causal.agency/lands.html b/www/causal.agency/lands.html
new file mode 100644
index 00000000..7aaadd80
--- /dev/null
+++ b/www/causal.agency/lands.html
@@ -0,0 +1,176 @@
+<!DOCTYPE html>
+<title>Lands Quiz</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<style>
+html { font: 14pt sans-serif; line-height: 1.5em; }
+body { padding: 1em 1ch; max-width: 78ch; margin: auto; }
+h1 { text-align: center; }
+h2 { margin-top: 0; }
+button { font-size: 100%; padding: 0.5em 1ch; }
+img { max-width: 100%; }
+div.cols { display: grid; grid-template-columns: 1fr 1fr; gap: 2ch; }
+</style>
+
+<h1 id="loading">Loading...</h1>
+<h1 id="error" hidden>Failed to load cards :(</h1>
+
+<div id="game" hidden>
+<h1>Magic Lands Quiz</h1>
+<p>Try to guess the colours of mana each land produces!</p>
+<div class="cols">
+	<div>
+		<img id="back" src="https://backs.scryfall.io/normal/0/a/0aeebaf5-8c7d-4636-9e82-8c27447861f7.jpg">
+		<a id="link" target="_blank">
+			<img id="image1" hidden>
+			<img id="image2" hidden>
+		</a>
+	</div>
+	<div>
+		<h2 id="name"></h2>
+		<input type="checkbox" id="w"> <label for="w">White</label><br>
+		<input type="checkbox" id="u"> <label for="u">Blue</label><br>
+		<input type="checkbox" id="b"> <label for="b">Black</label><br>
+		<input type="checkbox" id="r"> <label for="r">Red</label><br>
+		<input type="checkbox" id="g"> <label for="g">Green</label><br>
+		<p><button id="submit">Submit</button></p>
+		<h3>Score: <span id="score">0</span>/<span id="total">0</span></h3>
+	</div>
+</div>
+</div>
+
+<script>
+function shuffle(arr) {
+	let rand = (bound) => Math.floor(Math.random() * bound);
+	for (let i = arr.length-1; i > 0; --i) {
+		let j = rand(i+1);
+		let x = arr[i];
+		arr[i] = arr[j];
+		arr[j] = x;
+	}
+}
+
+const CardBack =
+"https://backs.scryfall.io/normal/0/a/0aeebaf5-8c7d-4636-9e82-8c27447861f7.jpg";
+
+function hideCard() {
+	document.getElementById("back").hidden = false;
+	document.getElementById("image1").hidden = true;
+	document.getElementById("image2").hidden = true;
+}
+
+function showCard(card) {
+	document.getElementById("back").hidden = true;
+	document.getElementById("link").href = card.scryfall_uri;
+	let image1 = document.getElementById("image1");
+	let image2 = document.getElementById("image2");
+	if (card.card_faces) {
+		image1.src = card.card_faces[0].image_uris.normal;
+		image2.src = card.card_faces[1].image_uris.normal;
+		image1.hidden = false;
+		image2.hidden = false;
+	} else {
+		image1.src = card.image_uris.normal;
+		image1.hidden = false;
+	}
+}
+
+function resetChecks() {
+	for (let c of "wubrg") {
+		let input = document.getElementById(c);
+		input.checked = false;
+		input.disabled = false;
+		input.labels[0].style.fontWeight = "normal";
+	}
+}
+
+function checkChecks(card) {
+	let score = 0;
+	let total = 0;
+	let checked = 0;
+	for (let c of "wubrg") {
+		let input = document.getElementById(c);
+		let produced = card.produced_mana.includes(c.toUpperCase());
+		if (produced) {
+			total++;
+			input.labels[0].style.fontWeight = "bold";
+			if (input.checked) score++;
+		}
+		if (input.checked) checked++;
+		input.disabled = true;
+	}
+	if (checked > total) score -= (checked - total);
+	if (score < 0) score = 0;
+	return { score: score, total: total };
+}
+
+document.onkeydown = function(event) {
+	for (let c of "wubrg") {
+		if (event.key == c) {
+			let input = document.getElementById(c);
+			if (!input.disabled) input.checked ^= true;
+		}
+	}
+	if (event.key == "Enter") {
+		document.getElementById("submit").click();
+	}
+}
+
+let score = 0;
+let total = 0;
+let cards = [];
+let card = null;
+
+function nextCard() {
+	hideCard();
+	resetChecks();
+	card = cards.shift();
+	document.getElementById("name").innerText = card.name;
+}
+
+document.getElementById("submit").onclick = function() {
+	if (card) {
+		let { score: cardScore, total: cardTotal } = checkChecks(card);
+		total += cardTotal;
+		score += cardScore;
+		document.getElementById("score").innerText = score;
+		document.getElementById("total").innerText = total;
+		showCard(card);
+		card = null;
+		if (cards.length) {
+			this.innerText = "Next card";
+		} else {
+			this.disabled = true;
+			this.innerText = "No more cards";
+		}
+	} else {
+		nextCard();
+		this.innerText = "Submit";
+	}
+}
+
+function loadCards(resp) {
+	let loading = document.getElementById("loading");
+	let error = document.getElementById("error");
+	let game = document.getElementById("game");
+	if (resp.status != 200) {
+		loading.hidden = true;
+		error.hidden = false;
+	}
+	resp.json().then((json) => {
+		cards.push(...json.data);
+		if (json.has_more) {
+			setTimeout(() => fetch(json.next_page).then(loadCards), 50);
+		} else {
+			loading.hidden = true;
+			game.hidden = false;
+			shuffle(cards);
+			nextCard();
+		}
+	});
+}
+
+const Search =
+"https://api.scryfall.com/cards/search?q=t:land+id>=2+produces>=2+produces!=wubrg";
+fetch(Search).then(loadCards);
+
+</script>
diff --git a/www/causal.agency/style.css b/www/causal.agency/style.css
new file mode 100644
index 00000000..265c62c2
--- /dev/null
+++ b/www/causal.agency/style.css
@@ -0,0 +1,28 @@
+@import url("scheme.css");
+
+table.head, table.foot { width: 100%; }
+td.head-rtitle, td.foot-os { text-align: right; }
+td.head-vol { text-align: center; }
+div.Pp { margin: 1ex 0ex; }
+div.Nd, div.Bf, div.Op { display: inline; }
+span.Pa, span.Ad { font-style: italic; }
+span.Ms { font-weight: bold; }
+dl.Bl-diag > dt { font-weight: bold; }
+code.Nm, code.Fl, code.Cm, code.Ic, code.In, code.Fd, code.Fn,
+code.Cd { font-weight: bold; font-family: inherit; }
+
+div.head, div.foot { display: flex; justify-content: space-between; }
+.head-ltitle, .foot-date { flex: 1; }
+.head-vol { flex: 0 1 auto; text-align: center; }
+.head-rtitle, .foot-os { flex: 1; text-align: right; }
+
+html { font-family: monospace; line-height: 1.25em; }
+body { max-width: 80ch; margin: 1em auto; padding: 0 1ch; }
+table { border-collapse: collapse; }
+table.Nm code.Nm { padding-right: 1ch; }
+table.foot { margin-top: 1em; }
+
+html { background-color: var(--ansi16); color: var(--ansi17); }
+a { color: var(--ansi4); }
+a:visited { color: var(--ansi5); }
+a.permalink { color: var(--ansi3); text-decoration: none; }