billion dollar idea: any/all pronouns except instead of actually writing "any/all" in your bio, you use a bot that automatically inserts a new set of pronouns every 10 seconds
it doesn't integrate with anything (and is ruined by caching (but not on cohost)), but you can type, e.g, https://pyrope.net/prngnouns?p=any&p=they/them&p=he/him&p=she/her&p=it/its and it will make an image like that.
it's a bit big i guess, but it doesn't look too terrible on my profile
question for computer nerds
i feel it would be a good idea to let color, size, etc be configurable using the url params, but i avoided doing that because i have a cache for images. i'm thinking that it would probably be better to just remove and remake the image on each request (especially considering that cleaning it up feels too heuristic). idk, would that be fine? would it be too slow? idk? here's the code as it is right now that would probably help (looks bad fsr, idc enough to fix it sorry)code
import { contentType } from "https://deno.land/std@0.202.0/media_types/mod.ts"; import { Image, TextLayout, } from "https://deno.land/x/imagescript@1.2.15/ImageScript.js";const font = await fetch("https://static.pyrope.net/courier-std-bold.otf")
.then((r) => r.arrayBuffer())
.then((b) => new Uint8Array(b));// deciding now: pronouns (e.g. he/him) can be at most 32 chars
let images: Map<string, { image: Uint8Array; fetched: number }> = new Map();
function make_image(s: string): Image {
console.log(`MAKING AN IMAGE FOR '${s}' (EXPENSIVE!)`);
let image = Image.renderText(
font,
64,
s,
0,
new TextLayout({ verticalAlign: "center", horizontalAlign: "middle" }),
);const outline = Image.renderText(
font,
64,
s,
0xff_ff_ff_ff,
new TextLayout({ verticalAlign: "center", horizontalAlign: "middle" }),
);for (const hshift of [-2, 0, 2]) {
for (const vshift of [-2, 0, 2]) {
image = image.composite(outline, hshift, vshift);
}
}
const text = Image.renderText(
font,
64,
s,
0x00_00_00_ff,
new TextLayout({ verticalAlign: "center", horizontalAlign: "middle" }),
);const final = image.composite(text);
return final.crop(0, 0, final.width, final.height - 22);
}async function get_pronoun_image(prn: string): Promise<Uint8Array> {
if (images.has(prn)) {
const entry = images.get(prn)!;
entry.fetched++;
return entry.image;
}
const image = await make_image(prn).encode();
images.set(prn, { image, fetched: 1 });
return image;
}// the whole cache thing def sketches me out, but people probably won't be that malicious
const MAX_PRN_LENGTH = 32;
const MAX_PRN_CACHE = 64;
// shouldn't really be a problem
const MAX_PRN_CHOICES = 128;function clean_up() {
if (images.size <= MAX_PRN_CACHE) {
console.log(
`not cleaning up, we only have ${images.size} cached which is less than ${MAX_PRN_CACHE}`,
);
return;
}// reverse order!
const entries = [...images.entries()].toSorted(([_a, a], [_b, b]) =>
b.fetched - a.fetched
);console.log("before clean up:", images);
images = new Map(entries.slice(0, MAX_PRN_CACHE));
console.log("after clean up:", images);
}const image_response = (data: Uint8Array): Response =>
new Response(data, {
headers: { "Content-Type": contentType("png") },
});Deno.serve({ port: 61265 }, async (req) => {
const prns = (new URL(req.url)).searchParams.getAll("p");if (prns.some((p) => p.length > MAX_PRN_LENGTH)) {
return new Response(`MAX_PRN_LENGTH = ${MAX_PRN_LENGTH}`, { status: 413 });
}if (prns.length > MAX_PRN_CHOICES) {
return new Response(`MAX_PRN_CHOICES = ${MAX_PRN_CHOICES}`, {
status: 413,
});
}const prn = prns[Math.floor(Math.random() * prns.length)] ??
"NONE, APPARENTLY";
const resp = image_response(await get_pronoun_image(prn));
clean_up();
return resp;
});

![terezi's head is seen from behind looking at the sky. on the right, it says terezi.pyrope.net and >:] terezi's head is seen from behind looking at the sky. on the right, it says terezi.pyrope.net and >:]](https://terezi.pyrope.net/88x31.png)
