diff --git a/website/assets/binkies/lel.gif b/website/assets/binkies/lel.gif
new file mode 100644
index 0000000..19e2ab7
Binary files /dev/null and b/website/assets/binkies/lel.gif differ
diff --git a/website/assets/cursor.ani b/website/assets/cursor.ani
deleted file mode 100644
index ceb9fb4..0000000
Binary files a/website/assets/cursor.ani and /dev/null differ
diff --git a/website/index.html b/website/index.html
index 2103876..79bb2c0 100644
--- a/website/index.html
+++ b/website/index.html
@@ -7,7 +7,6 @@ __TEMPLATE_HEAD__
-
diff --git a/website/scripts/ani_parser.ts b/website/scripts/ani_parser.ts
deleted file mode 100644
index 7fc7baf..0000000
--- a/website/scripts/ani_parser.ts
+++ /dev/null
@@ -1,225 +0,0 @@
-// Code by
-// https://www.npmjs.com/package/ani-cursor
-
-// When importing the NPM package it just doesn't work.
-// The babel version is so old it doesn't work on my browser.
-
-import { RIFFFile } from "riff-file";
-import { unpackArray, unpackString } from "byte-data";
-
-type Chunk = {
- format: string;
- chunkId: string;
- chunkData: {
- start: number;
- end: number;
- };
- subChunks: Chunk[];
-};
-
-// https://www.informit.com/articles/article.aspx?p=1189080&seqNum=3
-type AniMetadata = {
- cbSize: number; // Data structure size (in bytes)
- nFrames: number; // Number of images (also known as frames) stored in the file
- nSteps: number; // Number of frames to be displayed before the animation repeats
- iWidth: number; // Width of frame (in pixels)
- iHeight: number; // Height of frame (in pixels)
- iBitCount: number; // Number of bits per pixel
- nPlanes: number; // Number of color planes
- iDispRate: number; // Default frame display rate (measured in 1/60th-of-a-second units)
- bfAttributes: number; // ANI attribute bit flags
-};
-
-type ParsedAni = {
- rate: number[] | null;
- seq: number[] | null;
- images: Uint8Array[];
- metadata: AniMetadata;
- artist: string | null;
- title: string | null;
-};
-
-const DWORD = { bits: 32, be: false, signed: false, fp: false };
-
-export function parseAni(arr: Uint8Array): ParsedAni {
- const riff = new RIFFFile();
-
- riff.setSignature(arr);
-
- const signature = riff.signature as Chunk;
- if (signature.format !== "ACON") {
- throw new Error(
- `Expected format. Expected "ACON", got "${signature.format}"`
- );
- }
-
- // Helper function to get a chunk by chunkId and transform it if it's non-null.
- function mapChunk(chunkId: string, mapper: (chunk: Chunk) => T): T | null {
- const chunk = riff.findChunk(chunkId) as Chunk | null;
- return chunk == null ? null : mapper(chunk);
- }
-
- function readImages(chunk: Chunk, frameCount: number): Uint8Array[] {
- return chunk.subChunks.slice(0, frameCount).map((c) => {
- if (c.chunkId !== "icon") {
- throw new Error(`Unexpected chunk type in fram: ${c.chunkId}`);
- }
- return arr.slice(c.chunkData.start, c.chunkData.end);
- });
- }
-
- const metadata = mapChunk("anih", (c) => {
- const words = unpackArray(arr, DWORD, c.chunkData.start, c.chunkData.end);
- return {
- cbSize: words[0],
- nFrames: words[1],
- nSteps: words[2],
- iWidth: words[3],
- iHeight: words[4],
- iBitCount: words[5],
- nPlanes: words[6],
- iDispRate: words[7],
- bfAttributes: words[8],
- };
- });
-
- if (metadata == null) {
- throw new Error("Did not find anih");
- }
-
- const rate = mapChunk("rate", (c) => {
- return unpackArray(arr, DWORD, c.chunkData.start, c.chunkData.end);
- });
- // chunkIds are always four chars, hence the trailing space.
- const seq = mapChunk("seq ", (c) => {
- return unpackArray(arr, DWORD, c.chunkData.start, c.chunkData.end);
- });
-
- const lists = riff.findChunk("LIST", true) as Chunk[] | null;
- const imageChunk = lists?.find((c) => c.format === "fram");
- if (imageChunk == null) {
- throw new Error("Did not find fram LIST");
- }
-
- let images = readImages(imageChunk, metadata.nFrames);
-
- let title: string | null = null;
- let artist: string | null = null;
-
- const infoChunk = lists?.find((c) => c.format === "INFO");
- if (infoChunk != null) {
- infoChunk.subChunks.forEach((c) => {
- switch (c.chunkId) {
- case "INAM":
- title = unpackString(arr, c.chunkData.start, c.chunkData.end);
- break;
- case "IART":
- artist = unpackString(arr, c.chunkData.start, c.chunkData.end);
- break;
- case "LIST":
- // Some cursors with an artist of "Created with Take ONE 3.5 (unregisterred version)" seem to have their frames here for some reason?
- if (c.format === "fram") {
- images = readImages(c, metadata.nFrames);
- }
- break;
-
- default:
- // Unexpected subchunk
- }
- });
- }
-
- return { images, rate, seq, metadata, artist, title };
-}
-
-type AniCursorImage = {
- frames: {
- url: string;
- percents: number[];
- }[];
- duration: number;
-};
-
-const JIFFIES_PER_MS = 1000 / 60;
-
-// Generate CSS for an animated cursor.
-//
-// This function returns CSS containing a set of keyframes with embedded Data
-// URIs as well as a CSS rule to the given selector.
-export function convertAniBinaryToCSS(
- selector: string,
- aniBinary: Uint8Array
-): string {
- const ani = readAni(aniBinary);
-
- const animationName = `ani-cursor-${uniqueId()}`;
-
- const keyframes = ani.frames.map(({ url, percents }) => {
- const percent = percents.map((num) => `${num}%`).join(", ");
- return `${percent} { cursor: url(${url}), auto; }`;
- });
-
- // CSS properties with a animation type of "discrete", like `cursor`, actually
- // switch half-way _between_ each keyframe percentage. Luckily this half-way
- // measurement is applied _after_ the easing function is applied. So, we can
- // force the frames to appear at exactly the % that we specify by using
- // `timing-function` of `step-end`.
- //
- // https://drafts.csswg.org/web-animations-1/#discrete
- const timingFunction = "step-end";
-
- // Winamp (re)starts the animation cycle when your mouse enters an element. By
- // default this approach would cause the animation to run continuously, even
- // when the cursor is not visible. To match Winamp's behavior we add a
- // `:hover` pseudo selector so that the animation only runs when the cursor is
- // visible.
- const pseudoSelector = ":hover";
-
- // prettier-ignore
- return `
- @keyframes ${animationName} {
- ${keyframes.join("\n")}
- }
- ${selector}${pseudoSelector} {
- animation: ${animationName} ${ani.duration}ms ${timingFunction} infinite;
- }
- `;
-}
-
-function readAni(contents: Uint8Array): AniCursorImage {
- const ani = parseAni(contents);
- const rate = ani.rate ?? ani.images.map(() => ani.metadata.iDispRate);
- const duration = sum(rate);
-
- const frames = ani.images.map((image) => ({
- url: curUrlFromByteArray(image),
- percents: [] as number[],
- }));
-
- let elapsed = 0;
- rate.forEach((r, i) => {
- const frameIdx = ani.seq ? ani.seq[i] : i;
- frames[frameIdx].percents.push((elapsed / duration) * 100);
- elapsed += r;
- });
-
- return { duration: duration * JIFFIES_PER_MS, frames };
-}
-
-/* Utility Functions */
-
-let i = 0;
-const uniqueId = () => i++;
-
-function base64FromDataArray(dataArray: Uint8Array): string {
- return globalThis.window ? window.btoa(String.fromCharCode(...dataArray)) : Buffer.from(dataArray).toString("base64");
-}
-
-function curUrlFromByteArray(arr: Uint8Array) {
- const base64 = base64FromDataArray(arr);
- return `data:image/x-win-bitmap;base64,${base64}`;
-}
-
-function sum(values: number[]): number {
- return values.reduce((total, value) => total + value, 0);
-}
\ No newline at end of file
diff --git a/website/scripts/binkies.ts b/website/scripts/binkies.ts
index 743c329..284d02f 100644
--- a/website/scripts/binkies.ts
+++ b/website/scripts/binkies.ts
@@ -25,7 +25,8 @@ const binky = [
["https://bee.nekoweb.org/", "bee.png"],
["https://ultrakill.nekoweb.org/", "ultrakill.png"],
["https://immjs.dev", "immjs.gif"],
-
+ ["https://lel.nekoweb.org", "lel.gif"],
+
["insane.gif", "piracy.gif", "dsb.gif", "universe.gif", "css.png", "vscbutton.gif", "ezgif.gif"],
];
diff --git a/website/scripts/cursor.ts b/website/scripts/cursor.ts
deleted file mode 100644
index 2e14733..0000000
--- a/website/scripts/cursor.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { convertAniBinaryToCSS } from "./ani_parser";
-(async () => {
- const req = await fetch("/assets/cursor.ani");
- const buf = new Uint8Array(await req.arrayBuffer());
- const style = document.createElement("style");
- style.innerHTML = convertAniBinaryToCSS("body", buf);
- document.body.appendChild(style);
-})();