4
0
Fork 2
mirror of https://gerrit.hackerspace.pl/hscloud synced 2024-10-18 03:07:44 +00:00

hswaw/site: add badapple

Change-Id: I650ac3bf2a6b499c13c18ad05c26c9e18bbaaa24
Reviewed-on: https://gerrit.hackerspace.pl/c/hscloud/+/1945
Reviewed-by: radex <radex@hackerspace.pl>
Reviewed-by: pl <pl@hackerspace.pl>
This commit is contained in:
q3k 2024-03-25 23:26:14 +01:00 committed by q3k
parent e8c0952f45
commit 1d1aafb5b0
2 changed files with 92 additions and 0 deletions

View file

@ -265,9 +265,101 @@ class Life extends Animation {
}
}
// Obligatory bad apple animation.
// By q3k.
//
// Spritesheet was generated from the Youtube video UkgK8eUdpAo.
// $ ffmpeg -i input.webm \
// -filter:v "format=gray,crop=720:720,scale=16:16" \
// badapple-frames/frame%04d.png
//
// $ cat convert.py
// from PIL import Image
// import math
// nframes = 6572
// side = int(math.sqrt(nframes))
// if side * side < nframes:
// side += 1
// print('side', side)
// out = [[0 for _ in range(16 * side)] for _ in range(16 * side)]
// for i in range(nframes):
// ix = i % side
// iy = i // side
//
// img = Image.open(f'frame{i+1:04d}.png')
// for y in range(16):
// for x in range(16):
// v = img.getpixel((x, y))
// out[iy*16+y][ix*16+x] = v
// img = Image.new(mode='L', size=(side*16, side*16))
// for y in range(side*16):
// for x in range(side*16):
// img.putpixel((x, y), out[y][x])
// img.save('badapple.png')
class BadApple extends Animation {
// loadPixels. Not synchronous because I can't be arsed to make this code
// async friendly. That means you might call this, but end up with no
// this.pixels yet until stuff is ready.
loadPixels() {
// Only attempt to load once.
if (this.pixelsLoading === undefined) {
this.pixelsLoading = true;
} else {
return;
}
// Do the JS dance to actually get .png pixel data.
let img = new window.Image();
img.onload = () => {
let canvas = document.createElement('canvas');
let context = canvas.getContext('2d');
let width = img.width;
let height = img.height;
canvas.width = width;
canvas.height = height;
context.drawImage(img, 0, 0, width, height);
let imageData = context.getImageData(0, 0, width, height);
this.pixels = {
data: imageData.data,
width: width,
height: height,
};
};
img.src = "/static/site/badapple.png";
}
draw(ts) {
if (this.pixels === undefined) {
this.loadPixels();
return;
}
// Constants from generation script:
const side = 82;
const nframes = 6572;
const framerate = 30.0;
const frameno = Math.floor(ts * framerate) % nframes;
// Offset of frame within spritesheet.
const ix = frameno % side;
const iy = Math.floor(frameno / side);
for (let x = 0; x < 16; x++) {
for (let y = 0; y < 16; y++) {
// Pixel position within spritesheet.
const xx = ix * 16 + x;
const yy = iy * 16 + y;
// Get pixel data, convert to 0..1, assign.
let px = (yy * this.pixels.width + xx) * 4;
let v = this.pixels.data[px] / 256.0;
this.leds[x][y] = [v, v, v];
}
}
}
}
// Add your animations here:
export const animations = [
Life,
SnakeChase,
BadApple,
];

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 KiB