5) Write ‘genuary’
Yeah, this one got weird and recursive. But it’s only sort of font data, so I think it works.
Yeah, this one got weird and recursive. But it’s only sort of font data, so I think it works.
Perlin noise, but … really lowres? You can play with how low res or how many colors you want.
This is entirely based around this Fibonacci generator function:
function makeFibber(maxValue = 1000) {
let a = 1;
let b = 1;
return () => {
let n = a + b;
a = b;
b = n;
if (b > maxValue) {
a = 1;
b = 1;
}
return a;
};
}
Make a fibber and then just keep calling it for next values.
All sorts of exciting options here!
Twelve principles of animation
That … is a lot. And I’m not really an animator. But let’s see what we can do!
It’s been a couple years since I last did Genuary. Let’s do it again. I don’t expect to make any masterpieces, but I enjoy making tiny pretty pictures. It’s something I’ve been doing honestly as long as I’ve been programming (I remember making brownian motion ‘bugs’ in QBasic in the 90s…).
I play a lot of games on Board Game Arena (BGA!). A lot of those are turn based games with random people, but I have two subsets of games that I consider ‘more important’:
Unfortunately, the first tends to have longer ‘per turn’ times and the latter doesn’t have a timer at all, so both end up right at the very end of the sorted table list. But both, I’d rather play first and in-between other games.
Super niche problems, I know.
Generally, my solution has been to keep a tab open for each of those games in a Firefox Tab Group, but in those cases, I keep navigating off those pages accidentally (thank you next table button).
Super super niche problems, now.
In any case, I whipped up a quick userscript (I use ViolentMonkey) that will:
I recently had a conversation about parsing HTTPS/TLS/etc certificates client side (so that various values could be compared). There are, of course, libraries for that, but where’s the fun in that? Let’s dig in ourselves!
I thought of course it would be a well specified format and it wouldn’t take more than a few minutes to parse… right?
Right?
A quick random thing I learned that I found helpful (and you might too!):
async function hmac(text, secret) {
let enc = new TextEncoder("utf-8");
let algorithm = { name: "HMAC", hash: "SHA-256" };
let key = await crypto.subtle.importKey("raw", enc.encode(secret), algorithm, false, ["sign", "verify"]);
let signature = await crypto.subtle.sign(algorithm.name, key, enc.encode(text));
let digest = btoa(String.fromCharCode(...new Uint8Array(signature)));
return digest;
}
This is a function that uses the Web Crypto API to calculate a SHA-256 HMAC of a string given a secret value.
I mostly worked this out so that I could figure out how exactly TextEncoder worked, along with importKey (to turn a secret into proper key material) and also how to convert that back into a hex digest.
>> await hmac("lorem ipsum", "super secret")
"qArFX93Zi83ccIayhYnuFDpd4pk3eB4rZYDvNteobSU="
>> await hmac("lorem ipsum doler sit amet", "super secret")
"klTAioH5nNkguNhU2YcJshaZZtJW9DEb+MTqz4NWq8E="
>> await hmac("lorem ipsum", "even more super secret!")
"RoQLg2uz5KWLMJM72VExH5gZOls5bdZZyzHi678eDWs="
>> await hmac("lorem ipsum", "super secret")
"qArFX93Zi83ccIayhYnuFDpd4pk3eB4rZYDvNteobSU="
Disclaimer: This totally counts as rolling your own crypto. Don’t do this unless you know what you’re doing. 😄
Disclaimer disclaimer: I only rarely know what I’m doing. 😄 😄
Also, for what it’s worth, this is equivalent to the Python standard libraries’ hmac
+ base64
:
>>> base64.b64encode(hmac.digest(b'super secret', b'lorem ipsum', 'SHA256')).decode()
'qArFX93Zi83ccIayhYnuFDpd4pk3eB4rZYDvNteobSU='
Spend a month making one beautiful thing per day, given a bunch of prompts. A month late, but as they say, ’the second best time is now'.
Let’s do it!
Spend a month making one beautiful thing per day, given a bunch of prompts. A month late, but as they say, ’the second best time is now'.
Let’s do it!
let gui;
let params = {
lineWidth: 10,
minWidth: 50,
maxWidth: 100, maxWidthMax: 400,
minHeight: 50,
maxHeight: 100, maxHeightMax: 400,
colorChance: 0.1, colorChanceMin: 0, colorChanceMax: 1, colorChanceStep: 0.01,
}
let box;
let colors = [
"red",
"blue",
"yellow",
]
function setup() {
createCanvas(400, 400);
box = {
x: -params.lineWidth,
y: -params.lineWidth,
width: random(params.minWidth, params.maxWidth),
height: random(params.minHeight, params.maxHeight),
}
gui = createGuiPanel('params');
gui.addObject(params);
gui.setPosition(420, 0);
}
function draw() {
strokeWeight(params.lineWidth);
stroke("black");
if (random() < params.colorChance) {
fill(random(colors));
} else {
fill("white");
}
rect(box.x, box.y, box.width, box.height);
box.y += box.height;
box.height = random(params.minHeight, params.maxHeight);
if (box.y > height) {
box.x += box.width;
box.y = -params.lineWidth;
box.width = random(params.minWidth, params.maxWidth);
box.height = random(params.minHeight, params.maxHeight);
}
if (box.x > width) {
noLoop();
}
}
I did have a sketch before that that ended up getting a little un-minimal: