ani-cursor 0.0.5 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -7
- package/dist/__tests__/parser.test.js +25 -81
- package/dist/__tests__/parser.test.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +36 -52
- package/dist/index.js.map +1 -1
- package/dist/parser.d.ts +2 -2
- package/dist/parser.js +26 -30
- package/dist/parser.js.map +1 -1
- package/package.json +38 -10
- package/src/__tests__/parser.test.ts +1 -1
- package/src/index.ts +7 -3
- package/CHANGELOG.md +0 -11
package/README.md
CHANGED
|
@@ -8,12 +8,6 @@ I wrote a blog post about this library which you can find [here](https://jordane
|
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
|
-
```bash
|
|
12
|
-
yarn add ani-cursor
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
or
|
|
16
|
-
|
|
17
11
|
```bash
|
|
18
12
|
npm install ani-cursor
|
|
19
13
|
```
|
|
@@ -41,4 +35,4 @@ document.body.appendChild(h1);
|
|
|
41
35
|
applyCursor("#pizza", "https://archive.org/cors/tucows_169906_Pizza_cursor/pizza.ani");
|
|
42
36
|
```
|
|
43
37
|
|
|
44
|
-
Try the [Live Demo on CodeSandbox](https://codesandbox.io/s/jolly-thunder-9jkio?file=/src/index.js).
|
|
38
|
+
Try the [Live Demo on CodeSandbox](https://codesandbox.io/s/jolly-thunder-9jkio?file=/src/index.js).
|
|
@@ -1,92 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
-
function step(op) {
|
|
16
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
-
while (_) try {
|
|
18
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
-
switch (op[0]) {
|
|
21
|
-
case 0: case 1: t = op; break;
|
|
22
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
-
default:
|
|
26
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
-
if (t[2]) _.ops.pop();
|
|
31
|
-
_.trys.pop(); continue;
|
|
32
|
-
}
|
|
33
|
-
op = body.call(thisArg, _);
|
|
34
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
-
};
|
|
41
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
-
var fs_1 = __importDefault(require("fs"));
|
|
43
|
-
var path_1 = __importDefault(require("path"));
|
|
44
|
-
var __1 = require("../");
|
|
45
|
-
var LONG_BASE_64 = /([A-Za-z0-9+/=]{50})[A-Za-z0-9+/=]+/g;
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { convertAniBinaryToCSS } from "../index.js";
|
|
4
|
+
const LONG_BASE_64 = /([A-Za-z0-9+/=]{50})[A-Za-z0-9+/=]+/g;
|
|
46
5
|
// Parse a `.ani` in our fixture directory and trim down the image data for use
|
|
47
6
|
// in snapshot tests.
|
|
48
7
|
function readPathCss(filePath) {
|
|
49
|
-
|
|
50
|
-
return
|
|
8
|
+
const buffer = fs.readFileSync(path.join(__dirname, "./fixtures/", filePath));
|
|
9
|
+
return convertAniBinaryToCSS("#example", buffer).replace(LONG_BASE_64, "$1...");
|
|
51
10
|
}
|
|
52
11
|
// https://skins.webamp.org/skin/6e30f9e9b8f5719469809785ae5e4a1f/Super_Mario_Amp_2.wsz/
|
|
53
|
-
describe("Super_Mario_Amp_2.wsz",
|
|
54
|
-
test("eqslid.cur",
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
});
|
|
60
|
-
test("close.cur", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
61
|
-
return __generator(this, function (_a) {
|
|
62
|
-
expect(readPathCss("Super_Mario_Amp_2/close.cur")).toMatchSnapshot();
|
|
63
|
-
return [2 /*return*/];
|
|
64
|
-
});
|
|
65
|
-
}); });
|
|
12
|
+
describe("Super_Mario_Amp_2.wsz", () => {
|
|
13
|
+
test("eqslid.cur", async () => {
|
|
14
|
+
expect(readPathCss("Super_Mario_Amp_2/eqslid.cur")).toMatchSnapshot();
|
|
15
|
+
});
|
|
16
|
+
test("close.cur", async () => {
|
|
17
|
+
expect(readPathCss("Super_Mario_Amp_2/close.cur")).toMatchSnapshot();
|
|
18
|
+
});
|
|
66
19
|
});
|
|
67
20
|
// https://skins.webamp.org/skin/4308a2fc648033bf5fe7c4d56a5c8823/Green-Dimension-V2.wsz/
|
|
68
|
-
describe("Green Dimension v2.wsz",
|
|
69
|
-
test("eqslid.cur",
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return [2 /*return*/];
|
|
73
|
-
});
|
|
74
|
-
}); });
|
|
21
|
+
describe("Green Dimension v2.wsz", () => {
|
|
22
|
+
test("eqslid.cur", async () => {
|
|
23
|
+
expect(readPathCss("Green Dimension v2/eqslid.cur")).toMatchSnapshot();
|
|
24
|
+
});
|
|
75
25
|
});
|
|
76
|
-
describe("AfterShock_Digital_2003.wsz",
|
|
77
|
-
test("close.cur",
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return [2 /*return*/];
|
|
81
|
-
});
|
|
82
|
-
}); });
|
|
26
|
+
describe("AfterShock_Digital_2003.wsz", () => {
|
|
27
|
+
test("close.cur", async () => {
|
|
28
|
+
expect(readPathCss("AfterShock_Digital_2003/close.cur")).toMatchSnapshot();
|
|
29
|
+
});
|
|
83
30
|
});
|
|
84
|
-
describe("Edge cases",
|
|
85
|
-
test("piano.ani",
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return [2 /*return*/];
|
|
89
|
-
});
|
|
90
|
-
}); });
|
|
31
|
+
describe("Edge cases", () => {
|
|
32
|
+
test("piano.ani", async () => {
|
|
33
|
+
expect(readPathCss("piano.ani")).toMatchSnapshot();
|
|
34
|
+
});
|
|
91
35
|
});
|
|
92
36
|
//# sourceMappingURL=parser.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.test.js","sourceRoot":"","sources":["../../src/__tests__/parser.test.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"parser.test.js","sourceRoot":"","sources":["../../src/__tests__/parser.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,YAAY,GAAG,sCAAsC,CAAC;AAE5D,+EAA+E;AAC/E,qBAAqB;AACrB,SAAS,WAAW,CAAC,QAAgB;IACnC,MAAM,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE9E,OAAO,qBAAqB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,OAAO,CACtD,YAAY,EACZ,OAAO,CACR,CAAC;AACJ,CAAC;AAED,wFAAwF;AACxF,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,IAAI,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;QAC5B,MAAM,CAAC,WAAW,CAAC,8BAA8B,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC;IACxE,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE;QAC3B,MAAM,CAAC,WAAW,CAAC,6BAA6B,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC;IACvE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,yFAAyF;AACzF,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,IAAI,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;QAC5B,MAAM,CAAC,WAAW,CAAC,+BAA+B,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC;IACzE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,6BAA6B,EAAE,GAAG,EAAE;IAC3C,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE;QAC3B,MAAM,CAAC,WAAW,CAAC,mCAAmC,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC;IAC7E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE;QAC3B,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,39 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
4
|
-
if (!m) return o;
|
|
5
|
-
var i = m.call(o), r, ar = [], e;
|
|
6
|
-
try {
|
|
7
|
-
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
8
|
-
}
|
|
9
|
-
catch (error) { e = { error: error }; }
|
|
10
|
-
finally {
|
|
11
|
-
try {
|
|
12
|
-
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
13
|
-
}
|
|
14
|
-
finally { if (e) throw e.error; }
|
|
15
|
-
}
|
|
16
|
-
return ar;
|
|
17
|
-
};
|
|
18
|
-
var __spread = (this && this.__spread) || function () {
|
|
19
|
-
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
|
|
20
|
-
return ar;
|
|
21
|
-
};
|
|
22
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.convertAniBinaryToCSS = void 0;
|
|
24
|
-
var parser_1 = require("./parser");
|
|
25
|
-
var JIFFIES_PER_MS = 1000 / 60;
|
|
1
|
+
import { parseAni } from "./parser.js";
|
|
2
|
+
const JIFFIES_PER_MS = 1000 / 60;
|
|
26
3
|
// Generate CSS for an animated cursor.
|
|
27
4
|
//
|
|
28
5
|
// This function returns CSS containing a set of keyframes with embedded Data
|
|
29
6
|
// URIs as well as a CSS rule to the given selector.
|
|
30
|
-
function convertAniBinaryToCSS(selector, aniBinary) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return percent + " { cursor: url(" + url + "), auto; }";
|
|
7
|
+
export function convertAniBinaryToCSS(selector, aniBinary) {
|
|
8
|
+
const ani = readAni(aniBinary);
|
|
9
|
+
const animationName = `ani-cursor-${uniqueId()}`;
|
|
10
|
+
const keyframes = ani.frames.map(({ url, percents }) => {
|
|
11
|
+
const percent = percents.map((num) => `${num}%`).join(", ");
|
|
12
|
+
return `${percent} { cursor: url(${url}), auto; }`;
|
|
37
13
|
});
|
|
38
14
|
// CSS properties with a animation type of "discrete", like `cursor`, actually
|
|
39
15
|
// switch half-way _between_ each keyframe percentage. Luckily this half-way
|
|
@@ -42,45 +18,53 @@ function convertAniBinaryToCSS(selector, aniBinary) {
|
|
|
42
18
|
// `timing-function` of `step-end`.
|
|
43
19
|
//
|
|
44
20
|
// https://drafts.csswg.org/web-animations-1/#discrete
|
|
45
|
-
|
|
21
|
+
const timingFunction = "step-end";
|
|
46
22
|
// Winamp (re)starts the animation cycle when your mouse enters an element. By
|
|
47
23
|
// default this approach would cause the animation to run continuously, even
|
|
48
24
|
// when the cursor is not visible. To match Winamp's behavior we add a
|
|
49
25
|
// `:hover` pseudo selector so that the animation only runs when the cursor is
|
|
50
26
|
// visible.
|
|
51
|
-
|
|
27
|
+
const pseudoSelector = ":hover";
|
|
52
28
|
// prettier-ignore
|
|
53
|
-
return
|
|
29
|
+
return `
|
|
30
|
+
@keyframes ${animationName} {
|
|
31
|
+
${keyframes.join("\n")}
|
|
32
|
+
}
|
|
33
|
+
${selector}${pseudoSelector} {
|
|
34
|
+
animation: ${animationName} ${ani.duration}ms ${timingFunction} infinite;
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
54
37
|
}
|
|
55
|
-
exports.convertAniBinaryToCSS = convertAniBinaryToCSS;
|
|
56
38
|
function readAni(contents) {
|
|
57
39
|
var _a;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
40
|
+
const ani = parseAni(contents);
|
|
41
|
+
const rate = (_a = ani.rate) !== null && _a !== void 0 ? _a : ani.images.map(() => ani.metadata.iDispRate);
|
|
42
|
+
const duration = sum(rate);
|
|
43
|
+
const frames = ani.images.map((image) => ({
|
|
62
44
|
url: curUrlFromByteArray(image),
|
|
63
45
|
percents: [],
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
rate.forEach(
|
|
67
|
-
|
|
46
|
+
}));
|
|
47
|
+
let elapsed = 0;
|
|
48
|
+
rate.forEach((r, i) => {
|
|
49
|
+
const frameIdx = ani.seq ? ani.seq[i] : i;
|
|
68
50
|
frames[frameIdx].percents.push((elapsed / duration) * 100);
|
|
69
51
|
elapsed += r;
|
|
70
52
|
});
|
|
71
|
-
return { duration: duration * JIFFIES_PER_MS, frames
|
|
53
|
+
return { duration: duration * JIFFIES_PER_MS, frames };
|
|
72
54
|
}
|
|
73
55
|
/* Utility Functions */
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
function base64FromDataArray(dataArray) {
|
|
77
|
-
return window.btoa(
|
|
56
|
+
let i = 0;
|
|
57
|
+
const uniqueId = () => i++;
|
|
58
|
+
export function base64FromDataArray(dataArray) {
|
|
59
|
+
return window.btoa(Array.from(dataArray)
|
|
60
|
+
.map((byte) => String.fromCharCode(byte))
|
|
61
|
+
.join(""));
|
|
78
62
|
}
|
|
79
63
|
function curUrlFromByteArray(arr) {
|
|
80
|
-
|
|
81
|
-
return
|
|
64
|
+
const base64 = base64FromDataArray(arr);
|
|
65
|
+
return `data:image/x-win-bitmap;base64,${base64}`;
|
|
82
66
|
}
|
|
83
67
|
function sum(values) {
|
|
84
|
-
return values.reduce(
|
|
68
|
+
return values.reduce((total, value) => total + value, 0);
|
|
85
69
|
}
|
|
86
70
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/parser.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
type AniMetadata = {
|
|
2
2
|
cbSize: number;
|
|
3
3
|
nFrames: number;
|
|
4
4
|
nSteps: number;
|
|
@@ -9,7 +9,7 @@ declare type AniMetadata = {
|
|
|
9
9
|
iDispRate: number;
|
|
10
10
|
bfAttributes: number;
|
|
11
11
|
};
|
|
12
|
-
|
|
12
|
+
type ParsedAni = {
|
|
13
13
|
rate: number[] | null;
|
|
14
14
|
seq: number[] | null;
|
|
15
15
|
images: Uint8Array[];
|
package/dist/parser.js
CHANGED
|
@@ -1,31 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
var DWORD = { bits: 32, be: false, signed: false, fp: false };
|
|
7
|
-
function parseAni(arr) {
|
|
8
|
-
var riff = new riff_file_1.RIFFFile();
|
|
1
|
+
import { RIFFFile } from "riff-file";
|
|
2
|
+
import { unpackArray, unpackString } from "byte-data";
|
|
3
|
+
const DWORD = { bits: 32, be: false, signed: false, fp: false };
|
|
4
|
+
export function parseAni(arr) {
|
|
5
|
+
const riff = new RIFFFile();
|
|
9
6
|
riff.setSignature(arr);
|
|
10
|
-
|
|
7
|
+
const signature = riff.signature;
|
|
11
8
|
if (signature.format !== "ACON") {
|
|
12
|
-
throw new Error(
|
|
9
|
+
throw new Error(`Expected format. Expected "ACON", got "${signature.format}"`);
|
|
13
10
|
}
|
|
14
11
|
// Helper function to get a chunk by chunkId and transform it if it's non-null.
|
|
15
12
|
function mapChunk(chunkId, mapper) {
|
|
16
|
-
|
|
13
|
+
const chunk = riff.findChunk(chunkId);
|
|
17
14
|
return chunk == null ? null : mapper(chunk);
|
|
18
15
|
}
|
|
19
16
|
function readImages(chunk, frameCount) {
|
|
20
|
-
return chunk.subChunks.slice(0, frameCount).map(
|
|
17
|
+
return chunk.subChunks.slice(0, frameCount).map((c) => {
|
|
21
18
|
if (c.chunkId !== "icon") {
|
|
22
|
-
throw new Error(
|
|
19
|
+
throw new Error(`Unexpected chunk type in fram: ${c.chunkId}`);
|
|
23
20
|
}
|
|
24
21
|
return arr.slice(c.chunkData.start, c.chunkData.end);
|
|
25
22
|
});
|
|
26
23
|
}
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
const metadata = mapChunk("anih", (c) => {
|
|
25
|
+
const words = unpackArray(arr, DWORD, c.chunkData.start, c.chunkData.end);
|
|
29
26
|
return {
|
|
30
27
|
cbSize: words[0],
|
|
31
28
|
nFrames: words[1],
|
|
@@ -41,30 +38,30 @@ function parseAni(arr) {
|
|
|
41
38
|
if (metadata == null) {
|
|
42
39
|
throw new Error("Did not find anih");
|
|
43
40
|
}
|
|
44
|
-
|
|
45
|
-
return
|
|
41
|
+
const rate = mapChunk("rate", (c) => {
|
|
42
|
+
return unpackArray(arr, DWORD, c.chunkData.start, c.chunkData.end);
|
|
46
43
|
});
|
|
47
44
|
// chunkIds are always four chars, hence the trailing space.
|
|
48
|
-
|
|
49
|
-
return
|
|
45
|
+
const seq = mapChunk("seq ", (c) => {
|
|
46
|
+
return unpackArray(arr, DWORD, c.chunkData.start, c.chunkData.end);
|
|
50
47
|
});
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
const lists = riff.findChunk("LIST", true);
|
|
49
|
+
const imageChunk = lists === null || lists === void 0 ? void 0 : lists.find((c) => c.format === "fram");
|
|
53
50
|
if (imageChunk == null) {
|
|
54
51
|
throw new Error("Did not find fram LIST");
|
|
55
52
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
let images = readImages(imageChunk, metadata.nFrames);
|
|
54
|
+
let title = null;
|
|
55
|
+
let artist = null;
|
|
56
|
+
const infoChunk = lists === null || lists === void 0 ? void 0 : lists.find((c) => c.format === "INFO");
|
|
60
57
|
if (infoChunk != null) {
|
|
61
|
-
infoChunk.subChunks.forEach(
|
|
58
|
+
infoChunk.subChunks.forEach((c) => {
|
|
62
59
|
switch (c.chunkId) {
|
|
63
60
|
case "INAM":
|
|
64
|
-
title =
|
|
61
|
+
title = unpackString(arr, c.chunkData.start, c.chunkData.end);
|
|
65
62
|
break;
|
|
66
63
|
case "IART":
|
|
67
|
-
artist =
|
|
64
|
+
artist = unpackString(arr, c.chunkData.start, c.chunkData.end);
|
|
68
65
|
break;
|
|
69
66
|
case "LIST":
|
|
70
67
|
// Some cursors with an artist of "Created with Take ONE 3.5 (unregisterred version)" seem to have their frames here for some reason?
|
|
@@ -77,7 +74,6 @@ function parseAni(arr) {
|
|
|
77
74
|
}
|
|
78
75
|
});
|
|
79
76
|
}
|
|
80
|
-
return { images
|
|
77
|
+
return { images, rate, seq, metadata, artist, title };
|
|
81
78
|
}
|
|
82
|
-
exports.parseAni = parseAni;
|
|
83
79
|
//# sourceMappingURL=parser.js.map
|
package/dist/parser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ani-cursor",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Render .ani cursors as CSS animations in the browser",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
7
|
"types": "dist/index.d.ts",
|
|
7
|
-
"
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist/",
|
|
16
|
+
"src/**/*.ts"
|
|
17
|
+
],
|
|
8
18
|
"author": "Jordan Eldredge <jordan@jordaneldredge.com>",
|
|
9
19
|
"license": "MIT",
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=22.0.0"
|
|
22
|
+
},
|
|
10
23
|
"repository": {
|
|
11
24
|
"type": "git",
|
|
12
25
|
"url": "https://github.com/captbaritone/webamp.git",
|
|
@@ -18,23 +31,38 @@
|
|
|
18
31
|
"homepage": "https://github.com/captbaritone/webamp/tree/master/packages/ani-cursor",
|
|
19
32
|
"scripts": {
|
|
20
33
|
"build": "tsc",
|
|
34
|
+
"type-check": "tsc --noEmit",
|
|
35
|
+
"lint": "eslint src --ext ts,js",
|
|
21
36
|
"test": "jest",
|
|
22
37
|
"prepublish": "tsc"
|
|
23
38
|
},
|
|
24
39
|
"devDependencies": {
|
|
25
|
-
"@babel/core": "^7.
|
|
26
|
-
"@babel/preset-env": "^7.
|
|
27
|
-
"@babel/preset-typescript": "^7.
|
|
28
|
-
"@
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"typescript": "^4.1.2"
|
|
40
|
+
"@babel/core": "^7.20.0",
|
|
41
|
+
"@babel/preset-env": "^7.20.2",
|
|
42
|
+
"@babel/preset-typescript": "^7.20.0",
|
|
43
|
+
"@swc/jest": "^0.2.24",
|
|
44
|
+
"@types/node": "^24.0.10",
|
|
45
|
+
"typescript": "^5.6.2"
|
|
32
46
|
},
|
|
33
47
|
"dependencies": {
|
|
34
48
|
"byte-data": "18.1.1",
|
|
35
49
|
"riff-file": "^1.0.3"
|
|
36
50
|
},
|
|
37
51
|
"jest": {
|
|
38
|
-
"modulePathIgnorePatterns": [
|
|
52
|
+
"modulePathIgnorePatterns": [
|
|
53
|
+
"dist"
|
|
54
|
+
],
|
|
55
|
+
"testEnvironment": "jsdom",
|
|
56
|
+
"extensionsToTreatAsEsm": [
|
|
57
|
+
".ts"
|
|
58
|
+
],
|
|
59
|
+
"moduleNameMapper": {
|
|
60
|
+
"^(\\.{1,2}/.*)\\.js$": "$1"
|
|
61
|
+
},
|
|
62
|
+
"transform": {
|
|
63
|
+
"^.+\\.(t|j)sx?$": [
|
|
64
|
+
"@swc/jest"
|
|
65
|
+
]
|
|
66
|
+
}
|
|
39
67
|
}
|
|
40
68
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseAni } from "./parser";
|
|
1
|
+
import { parseAni } from "./parser.js";
|
|
2
2
|
|
|
3
3
|
type AniCursorImage = {
|
|
4
4
|
frames: {
|
|
@@ -79,8 +79,12 @@ function readAni(contents: Uint8Array): AniCursorImage {
|
|
|
79
79
|
let i = 0;
|
|
80
80
|
const uniqueId = () => i++;
|
|
81
81
|
|
|
82
|
-
function base64FromDataArray(dataArray: Uint8Array): string {
|
|
83
|
-
return window.btoa(
|
|
82
|
+
export function base64FromDataArray(dataArray: Uint8Array): string {
|
|
83
|
+
return window.btoa(
|
|
84
|
+
Array.from(dataArray)
|
|
85
|
+
.map((byte) => String.fromCharCode(byte))
|
|
86
|
+
.join("")
|
|
87
|
+
);
|
|
84
88
|
}
|
|
85
89
|
|
|
86
90
|
function curUrlFromByteArray(arr: Uint8Array) {
|
package/CHANGELOG.md
DELETED