anime-cursor 0.1.0 → 0.1.2

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 CHANGED
@@ -1,10 +1,10 @@
1
1
  # AnimeCursor
2
2
 
3
3
  <div align="center">
4
- <img src="title.gif" width="60%" alt="AnimeCursor"/>
4
+ <img src="https://cdn.jsdelivr.net/gh/shuninyu/anime-cursor@main/title.gif" width="60%" alt="AnimeCursor"/>
5
5
  </div>
6
6
 
7
- [[简体中文]](#SChinese)
7
+ [[简体中文]](#animecursorsc)
8
8
 
9
9
  AnimeCursor is a lightweight animated cursor JS library that enables dynamic mouse pointers for websites.
10
10
 
@@ -21,18 +21,30 @@ AnimeCursor has no dependencies on any frameworks, making it suitable for person
21
21
  * Prepare PNG sprite sheets in the correct format, and AnimeCursor will automatically generate cursor animations based on your settings
22
22
  * Built with native JavaScript, no third-party dependencies
23
23
 
24
- ---
25
-
26
24
  ## 📦 Installation
27
25
 
26
+ ### CDN
27
+
28
+ ```html
29
+ <script src="https://cdn.jsdelivr.net/npm/anime-cursor/dist/anime-cursor.umd.min.js"></script>
30
+ ```
31
+
32
+ ### npm
33
+
34
+ ```bash
35
+ npm i anime-cursor
36
+ ```
37
+ ```js
38
+ import AnimeCursor from 'anime-cursor';
39
+ new AnimeCursor({...});
40
+ ```
41
+
28
42
  ### Local storage
29
43
 
30
44
  ```html
31
45
  <script src="anime-cursor.umd.min.js"></script>
32
46
  ```
33
47
 
34
- ---
35
-
36
48
  ## 🚀 Basic Usage
37
49
 
38
50
  Here is an example of how to use AnimeCursor:
@@ -41,28 +53,33 @@ Here is an example of how to use AnimeCursor:
41
53
  <script>
42
54
  new AnimeCursor({
43
55
  cursors: {
56
+ // each type of cursor needs tags, size and image
44
57
  default: {
45
- tags: ['body'],
58
+ tags: ['body'], // default cursor recommended setting
46
59
  size: [64,64],
47
- image: './cursor_default.png',
48
- frames: 1
60
+ image: './cursor_default.png' // static cursor only needs image
49
61
  },
62
+ // png sprite animated cursor needs frames and duration
50
63
  pointer: {
51
64
  tags: ['a', 'button'],
52
65
  size: [64,64],
53
66
  image: './cursor_pointer.png',
54
67
  frames: 3,
55
68
  duration: 0.3,
56
- pingpong: true,
57
- offset: [10, 4]
69
+ pingpong: true, // enable pingpong loop
70
+ offset: [10, 4] // if the pointing spot is not at the top left of the image, set offset
71
+ },
72
+ // gif cursor doesn't needs frames and duration
73
+ text: {
74
+ tags: ['p', 'h1', 'h2', 'span'],
75
+ size: [32, 64],
76
+ image: './cursor_text.gif'
58
77
  }
59
78
  }
60
79
  });
61
80
  </script>
62
81
  ```
63
82
 
64
- ---
65
-
66
83
  ## ⚙️ Configuration Options
67
84
 
68
85
  ### `cursors` (Required)
@@ -79,11 +96,11 @@ For each key, the following parameters can be set. Missing required parameters w
79
96
  |-|-|-|-|
80
97
  | `tags` | `string[]` | ✅ | HTML tags that should use this cursor |
81
98
  | `size` | `number` | ✅ | Cursor dimensions [width, height] in pixels |
82
- | `offset` | `[number, number]` | | Cursor alignment offset [ x , y ] |
83
99
  | `image` | `string` | ✅ | Image path (PNG / GIF) |
84
- | `frames` | `number` | ✅ | Number of frames for PNG sprites (set to `1` for static images) |
100
+ | `frames` | `number` || Number of frames for PNG sprites (set to `1` for static images) |
85
101
  | `duration` | `number` | | Animation loop duration (seconds) ⚠️ PNG sprite animations *only* work when this parameter is set |
86
102
  | `pingpong` | `boolean` | | Enable ping-pong (back-and-forth) looping (for PNG sprite animations only) |
103
+ | `offset` | `[number, number]` | | Cursor alignment offset [ x , y ] ⚠️ This parameter is not affected by `scale`|
87
104
  | `scale` | `[number, number]` | | Cursor scale factor based on `size` [ x , y ] ⚠️ Only supported for GIF cursors. Do not set for PNG sprite cursors, as it will break the animation. |
88
105
  | `pixel` | `boolean` | | Enable pixelated rendering |
89
106
  | `zIndex` | `number` | | Cursor z-index layer (not recommended to modify) |
@@ -101,13 +118,11 @@ Enables animated cursors on mobile touch devices.
101
118
  AnimeCursor automatically detects mobile touch devices (e.g., phones, tablets) and disables animated cursors on them by default.
102
119
  If you want animated cursors to be displayed on these devices, add `enableTouch: true`.
103
120
 
104
- ---
105
-
106
121
  ## 📝 Notes
107
122
 
108
123
  ### 📁 Files
109
124
 
110
- * For any PNG sprite animation cursor, its PNG sprite sheet should be arranged in a single horizontal row. AnimeCursor will automatically generate the PNG sprite animation.
125
+ * **For any PNG sprite animation cursor, its PNG sprite sheet should be arranged in a single horizontal row.** AnimeCursor will automatically generate the PNG sprite animation.
111
126
  For example, if you set the `size` (width, height) for a `pointer` cursor to `[64px , 64px]` and `frames` to `3`, the prepared sprite sheet dimensions (width, height) should be: `[192px , 64px]`.
112
127
 
113
128
  * For pixel art with a large number of frames, you can use the original image (whether GIF or PNG-sprite-sheet) to save storage space or bandwidth. Then, use the `scale` parameter in the configuration to resize the cursor and set `pixel` to `true` to avoid blurry scaling.
@@ -135,7 +150,7 @@ Therefore, to assign a specific animated cursor to a particular element, simply
135
150
  Animation is generated **only when all of the following conditions are met**:
136
151
 
137
152
  * The image is a PNG
138
- * `frames > 1`
153
+ * `frames` is set and `frames > 1`
139
154
  * `duration` is set
140
155
 
141
156
  If `duration` is not set, the cursor will be treated as a **static cursor**, even if `frames > 1`.
@@ -145,8 +160,6 @@ If `duration` is not set, the cursor will be treated as a **static cursor**, eve
145
160
  * GIFs do not use `frames`, `duration`, or `pingpong`
146
161
  * Animation is controlled by the GIF file itself
147
162
 
148
- ---
149
-
150
163
  ## ❌ Error Handling
151
164
 
152
165
  * Missing required configuration parameters will directly terminate initialization.
@@ -154,10 +167,10 @@ If `duration` is not set, the cursor will be treated as a **static cursor**, eve
154
167
  * All errors are prefixed with `[AnimeCursor]` when logged to the console.
155
168
 
156
169
  ---
157
- <h1 id="SChinese">AnimeCursor</h1>
170
+ # AnimeCursor(SC)
158
171
 
159
172
  <div align="center">
160
- <img src="title.gif" width="60%" alt="AnimeCursor"/>
173
+ <img src="https://cdn.jsdelivr.net/gh/shuninyu/anime-cursor@main/title.gif" width="60%" alt="AnimeCursor"/>
161
174
  </div>
162
175
 
163
176
  AnimeCursor 是一个轻量级动画光标JS,能够让网站拥有动态的鼠标指针。
@@ -175,9 +188,23 @@ AnimeCursor 无需依赖任何框架,适合个人网站、创意作品集以
175
188
  * 按照格式准备好 PNG 精灵图表,AnimeCursor 将基于你的设置自动生成光标动画
176
189
  * 基于原生JavaScript,无任何第三方依赖
177
190
 
178
- ---
191
+ ## 📦 部署方法
192
+
193
+ ### CDN
179
194
 
180
- ## 📦 引入方式
195
+ ```html
196
+ <script src="https://cdn.jsdelivr.net/npm/anime-cursor/dist/anime-cursor.umd.min.js"></script>
197
+ ```
198
+
199
+ ### npm
200
+
201
+ ```bash
202
+ npm i anime-cursor
203
+ ```
204
+ ```js
205
+ import AnimeCursor from 'anime-cursor';
206
+ new AnimeCursor({...});
207
+ ```
181
208
 
182
209
  ### 本地部署
183
210
 
@@ -185,8 +212,6 @@ AnimeCursor 无需依赖任何框架,适合个人网站、创意作品集以
185
212
  <script src="anime-cursor.umd.min.js"></script>
186
213
  ```
187
214
 
188
- ---
189
-
190
215
  ## 🚀 基础用法
191
216
 
192
217
  下面是一个 AnimeCursor 使用示例:
@@ -194,28 +219,33 @@ AnimeCursor 无需依赖任何框架,适合个人网站、创意作品集以
194
219
  <script>
195
220
  new AnimeCursor({
196
221
  cursors: {
222
+ // 每种光标都需要 tags size 和 image
197
223
  default: {
198
- tags: ['body'],
224
+ tags: ['body'], // 默认光标推荐照此设置
199
225
  size: [64,64],
200
- image: './cursor_default.png',
201
- frames: 1
226
+ image: './cursor_default.png' // 静态光标只需要图片链接
202
227
  },
228
+ // png 精灵图动画光标还需要 frames 和 duration
203
229
  pointer: {
204
230
  tags: ['a', 'button'],
205
231
  size: [64,64],
206
232
  image: './cursor_pointer.png',
207
233
  frames: 3,
208
234
  duration: 0.3,
209
- pingpong: true,
210
- offset: [10, 4]
235
+ pingpong: true, // enable pingpong loop
236
+ offset: [10, 4] // if the pointing spot is not at the top left of the image, set offset
237
+ },
238
+ // gif 光标不需要 frames 或 duration
239
+ text: {
240
+ tags: ['p', 'h1', 'h2', 'span'],
241
+ size: [32, 64],
242
+ image: './cursor_text.gif'
211
243
  }
212
244
  }
213
245
  });
214
246
  </script>
215
247
  ```
216
248
 
217
- ---
218
-
219
249
  ## ⚙️ 配置项说明
220
250
 
221
251
  ### `cursors`(必填)
@@ -232,11 +262,11 @@ new AnimeCursor({
232
262
  |-|-|-|-|
233
263
  |`tags`|`string[]`|✅|使用该光标的 HTML 标签|
234
264
  |`size`|`number`|✅|光标尺寸(宽高,像素)|
235
- |`offset`|`[number, number]`||光标对齐偏移量 [ x , y ]|
236
265
  |`image`|`string`|✅|图片路径(PNG / GIF)|
237
- |`frames`|`number`|✅|PNG 帧数(静态图片请设置为 `1` )|
266
+ |`frames`|`number`||PNG 帧数(静态图片请设置为 `1` )|
238
267
  |`duration`|`number`||动画循环时长(秒)⚠️PNG精灵图动画只有设置该参数才会生效|
239
268
  |`pingpong`|`boolean`||是否启用乒乓循环(仅PNG精灵图动画)|
269
+ |`offset`|`[number, number]`||光标对齐偏移量 [ x , y ]⚠️此参数不受 `scale` 影响|
240
270
  |`scale`|`[number, number]`||基于size的光标缩放 [ x , y ]⚠️仅支持GIF光标,PNG精灵图动画光标请勿设置,否则会使动画失效|
241
271
  |`pixel`|`boolean`||是否启用像素化渲染|
242
272
  |`zIndex`|`number`||光标层级(不建议添加此项设置)|
@@ -254,13 +284,11 @@ debug覆盖会显示鼠标的真实位置以及当前光标类型,以帮助纠
254
284
  AnimeCursor 会自动识别移动触屏设备(比如手机、平板电脑)并默认屏蔽这些设备上的动画光标。
255
285
  如果你想在这些设备上显示动画光标,可以添加 `enableTouch: true` 。
256
286
 
257
- ---
258
-
259
287
  ## 📝 注意事项
260
288
 
261
289
  ### 📁 文件
262
290
 
263
- * 对于任何 PNG 精灵图动画光标,它的 PNG 精灵图表都应该为单行横向布局,AnimeCursor 会自动生成 PNG 精灵图动画。
291
+ * **对于任何 PNG 精灵图动画光标,它的 PNG 精灵图表都应该为单行横向布局,** AnimeCursor 会自动生成 PNG 精灵图动画。
264
292
  例如,你为 `pointer` 光标设置的`size`(长,宽)为 `[64px , 64px]` ,帧数为 `3` ,那么你准备的精灵图表尺寸(长,宽)应该为: `[192px , 64px]` 。
265
293
 
266
294
  * 对于帧数特别多的像素图,你可以使用原尺寸图片(无论是gif还是png精灵图表)以节省存储空间或带宽,并在参数中设置 `scale` 来缩放光标,并将 `pixel` 设置为 `true` 来避免缩放模糊。
@@ -288,7 +316,7 @@ AnimeCursor 会根据配置自动为页面元素添加 `data-cursor`:
288
316
  只有在 **同时满足以下条件** 时,才会生成动画:
289
317
 
290
318
  * 图片为 PNG
291
- * `frames > 1`
319
+ * 设置了 `frames` 且 `frames > 1`
292
320
  * 设置了 `duration`
293
321
 
294
322
  如果未设置 `duration`,即使帧数大于 1,也会被视为**静态光标**。
@@ -298,8 +326,6 @@ AnimeCursor 会根据配置自动为页面元素添加 `data-cursor`:
298
326
  * GIF 不使用 `frames`、`duration` 或 `pingpong`
299
327
  * 动画由 GIF 自身控制
300
328
 
301
- ---
302
-
303
329
  ## ❌ 错误处理
304
330
 
305
331
  * 缺少必填配置会直接终止初始化
@@ -1,3 +1,6 @@
1
+ // AnimeCursor by github@ShuninYu
2
+ // v0.1.2
3
+
1
4
  class AnimeCursor {
2
5
 
3
6
  constructor(options = {}) {
@@ -46,7 +49,7 @@ class AnimeCursor {
46
49
  }
47
50
 
48
51
  for (const [name, cfg] of Object.entries(this.options.cursors)) {
49
- const required = ['tags', 'size', 'image', 'frames'];
52
+ const required = ['tags', 'size', 'image'];
50
53
  required.forEach(key => {
51
54
  if (cfg[key] === undefined) {
52
55
  console.error(`[AnimeCursor] 光标 "${name}" 缺少必填项:${key}`);
@@ -87,13 +90,13 @@ class AnimeCursor {
87
90
  }
88
91
 
89
92
  // ----------------------------
90
- // 插入基础 CSS
93
+ // 插入样式 CSS
91
94
  // ----------------------------
92
95
  _injectCSS() {
93
96
  const style = document.createElement('style');
94
97
  let css = '';
95
98
 
96
- /* 通用样式和debug样式 */
99
+ /* 通用样式 */
97
100
  css += `
98
101
  * {
99
102
  cursor: none !important;
@@ -4,6 +4,9 @@
4
4
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.AnimeCursor = factory());
5
5
  })(this, (function () { 'use strict';
6
6
 
7
+ // AnimeCursor by github@ShuninYu
8
+ // v0.1.2
9
+
7
10
  class AnimeCursor {
8
11
 
9
12
  constructor(options = {}) {
@@ -52,7 +55,7 @@
52
55
  }
53
56
 
54
57
  for (const [name, cfg] of Object.entries(this.options.cursors)) {
55
- const required = ['tags', 'size', 'image', 'frames'];
58
+ const required = ['tags', 'size', 'image'];
56
59
  required.forEach(key => {
57
60
  if (cfg[key] === undefined) {
58
61
  console.error(`[AnimeCursor] 光标 "${name}" 缺少必填项:${key}`);
@@ -93,13 +96,13 @@
93
96
  }
94
97
 
95
98
  // ----------------------------
96
- // 插入基础 CSS
99
+ // 插入样式 CSS
97
100
  // ----------------------------
98
101
  _injectCSS() {
99
102
  const style = document.createElement('style');
100
103
  let css = '';
101
104
 
102
- /* 通用样式和debug样式 */
105
+ /* 通用样式 */
103
106
  css += `
104
107
  * {
105
108
  cursor: none !important;
@@ -1 +1 @@
1
- !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e="undefined"!=typeof globalThis?globalThis:e||self).AnimeCursor=n()}(this,function(){"use strict";return class{constructor(e={}){if(this.options={enableTouch:!1,debug:!1,...e},this.disabled=!1,!this.options.enableTouch&&!this.isMouseLikeDevice())return this.disabled=!0,void(this.options.debug&&console.warn("[AnimeCursor] Touch device detected, cursor disabled."));this.cursorEl=null,this.lastCursorType=null,this.debugEl=null,this._validateOptions(),this._injectHTML(),this._injectCSS(),this._bindElements(),this._bindMouse()}isMouseLikeDevice(){return window.matchMedia("(pointer: fine)").matches}destroy(){this.disabled}_validateOptions(){if(!this.options||!this.options.cursors)throw console.error("[AnimeCursor] 缺少 cursors 配置"),new Error("AnimeCursor init failed");for(const[e,n]of Object.entries(this.options.cursors)){if(["tags","size","image","frames"].forEach(t=>{if(void 0===n[t])throw console.error(`[AnimeCursor] 光标 "${e}" 缺少必填项:${t}`),new Error("AnimeCursor init failed")}),!Array.isArray(n.tags))throw console.error(`[AnimeCursor] 光标 "${e}" 的 tags 必须是数组`),new Error("AnimeCursor init failed");if(void 0!==n.duration&&"number"!=typeof n.duration)throw console.error(`[AnimeCursor] 光标 "${e}" 的 duration 必须是数字(秒)`),new Error("AnimeCursor init failed")}}_injectHTML(){const e=document.createElement("div");if(e.id="anime-cursor",this.options.debug){e.className="cursor-default cursor-debugmode";const n=document.createElement("div");n.className="anime-cursor-debug",document.body.appendChild(n),this.debugEl=n}else e.className="cursor-default";document.body.appendChild(e),this.cursorEl=e}_injectCSS(){const e=document.createElement("style");let n="";n+=`\n* {\ncursor: none !important;\n}\n#anime-cursor {\nposition: fixed;\ntop: 0;\nleft: 0;\npointer-events: none;\nbackground-repeat: no-repeat;\ntransform-origin: 0 0;\ntransform-style: preserve-3d;\nz-index: ${this._getMaxZIndex()};\n}\n.cursor-debugmode {\n border: 1px solid green;\n}\n.anime-cursor-debug {\n position: fixed;\n top: 0;\n left: 0;\n width: fit-content;\n height: fit-content;\n padding: 5px;\n font-size: 16px;\n text-wrap: nowrap;\n color: red;\n pointer-events: none;\n overflow: visible;\n z-index: 2147483647;\n}\n.anime-cursor-debug::before {\n position: absolute;\n content: "";\n top: 0;\n left: 0;\n width: 100vw;\n height: 1px;\n background-color: red;\n}\n.anime-cursor-debug::after {\n position: absolute;\n content: "";\n top: 0;\n left: 0;\n width: 1px;\n height: 100vh;\n background-color: red;\n}\n`;for(const[e,o]of Object.entries(this.options.cursors)){const r=`.cursor-${e}`,s=o.size,i=o.frames,d=o.image,u=o.offset,a=o.zIndex,c=o.scale,l=d.toLowerCase().endsWith(".gif");var t;t=o.pixel?"pixelated":"auto",n+=`\n${r} {\nwidth: ${s[0]}px;\nheight: ${s[1]}px;\nbackground-image: url("${d}");\nimage-rendering: ${t};\n${c||u?`transform: ${[c&&`scale(${c[0]}, ${c[1]})`,u&&`translate(-${u[0]}px, -${u[1]}px)`].filter(Boolean).join(" ")};`:""}\n \n${void 0!==a?`z-index:${a};`:""}\n}`;const p=o.duration;if(!l&&i>1&&"number"==typeof p){const t=`animecursor_${e}`;n+=`\n${r} {\nanimation: ${t} steps(${i}) ${p}s infinite ${o.pingpong?"alternate":""};\n}\n\n@keyframes ${t} {\nfrom { background-position: 0 0; }\nto { background-position: -${s[0]*i}px 0; }\n}\n`}}e.textContent=n,document.head.appendChild(e)}_bindElements(){for(const[e,n]of Object.entries(this.options.cursors))n.tags.forEach(n=>{const t=n.toUpperCase();document.querySelectorAll(t).forEach(n=>{n.dataset.cursor||(n.dataset.cursor=e)})})}_bindMouse(){document.addEventListener("mousemove",e=>{const n=e.clientX,t=e.clientY;this.cursorEl.style.left=n+"px",this.cursorEl.style.top=t+"px",this.debugEl&&(this.debugEl.style.left=n+"px",this.debugEl.style.top=t+"px");const o=document.elementFromPoint(n,t);if(!o)return;const r=o.dataset.cursor||"default";this.debugEl&&(this.debugEl.textContent=`(${n}px , ${t}px) ${r}`),r!==this.lastCursorType&&(this.debugEl?this.cursorEl.className=`cursor-${r} cursor-debugmode`:this.cursorEl.className=`cursor-${r}`,this.lastCursorType=r)})}_getMaxZIndex(){return 2147483646}}});
1
+ !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e="undefined"!=typeof globalThis?globalThis:e||self).AnimeCursor=n()}(this,function(){"use strict";return class{constructor(e={}){if(this.options={enableTouch:!1,debug:!1,...e},this.disabled=!1,!this.options.enableTouch&&!this.isMouseLikeDevice())return this.disabled=!0,void(this.options.debug&&console.warn("[AnimeCursor] Touch device detected, cursor disabled."));this.cursorEl=null,this.lastCursorType=null,this.debugEl=null,this._validateOptions(),this._injectHTML(),this._injectCSS(),this._bindElements(),this._bindMouse()}isMouseLikeDevice(){return window.matchMedia("(pointer: fine)").matches}destroy(){this.disabled}_validateOptions(){if(!this.options||!this.options.cursors)throw console.error("[AnimeCursor] 缺少 cursors 配置"),new Error("AnimeCursor init failed");for(const[e,n]of Object.entries(this.options.cursors)){if(["tags","size","image"].forEach(t=>{if(void 0===n[t])throw console.error(`[AnimeCursor] 光标 "${e}" 缺少必填项:${t}`),new Error("AnimeCursor init failed")}),!Array.isArray(n.tags))throw console.error(`[AnimeCursor] 光标 "${e}" 的 tags 必须是数组`),new Error("AnimeCursor init failed");if(void 0!==n.duration&&"number"!=typeof n.duration)throw console.error(`[AnimeCursor] 光标 "${e}" 的 duration 必须是数字(秒)`),new Error("AnimeCursor init failed")}}_injectHTML(){const e=document.createElement("div");if(e.id="anime-cursor",this.options.debug){e.className="cursor-default cursor-debugmode";const n=document.createElement("div");n.className="anime-cursor-debug",document.body.appendChild(n),this.debugEl=n}else e.className="cursor-default";document.body.appendChild(e),this.cursorEl=e}_injectCSS(){const e=document.createElement("style");let n="";n+=`\n* {\ncursor: none !important;\n}\n#anime-cursor {\nposition: fixed;\ntop: 0;\nleft: 0;\npointer-events: none;\nbackground-repeat: no-repeat;\ntransform-origin: 0 0;\ntransform-style: preserve-3d;\nz-index: ${this._getMaxZIndex()};\n}\n.cursor-debugmode {\n border: 1px solid green;\n}\n.anime-cursor-debug {\n position: fixed;\n top: 0;\n left: 0;\n width: fit-content;\n height: fit-content;\n padding: 5px;\n font-size: 16px;\n text-wrap: nowrap;\n color: red;\n pointer-events: none;\n overflow: visible;\n z-index: 2147483647;\n}\n.anime-cursor-debug::before {\n position: absolute;\n content: "";\n top: 0;\n left: 0;\n width: 100vw;\n height: 1px;\n background-color: red;\n}\n.anime-cursor-debug::after {\n position: absolute;\n content: "";\n top: 0;\n left: 0;\n width: 1px;\n height: 100vh;\n background-color: red;\n}\n`;for(const[e,o]of Object.entries(this.options.cursors)){const r=`.cursor-${e}`,s=o.size,i=o.frames,d=o.image,u=o.offset,a=o.zIndex,c=o.scale,l=d.toLowerCase().endsWith(".gif");var t;t=o.pixel?"pixelated":"auto",n+=`\n${r} {\nwidth: ${s[0]}px;\nheight: ${s[1]}px;\nbackground-image: url("${d}");\nimage-rendering: ${t};\n${c||u?`transform: ${[c&&`scale(${c[0]}, ${c[1]})`,u&&`translate(-${u[0]}px, -${u[1]}px)`].filter(Boolean).join(" ")};`:""}\n \n${void 0!==a?`z-index:${a};`:""}\n}`;const p=o.duration;if(!l&&i>1&&"number"==typeof p){const t=`animecursor_${e}`;n+=`\n${r} {\nanimation: ${t} steps(${i}) ${p}s infinite ${o.pingpong?"alternate":""};\n}\n\n@keyframes ${t} {\nfrom { background-position: 0 0; }\nto { background-position: -${s[0]*i}px 0; }\n}\n`}}e.textContent=n,document.head.appendChild(e)}_bindElements(){for(const[e,n]of Object.entries(this.options.cursors))n.tags.forEach(n=>{const t=n.toUpperCase();document.querySelectorAll(t).forEach(n=>{n.dataset.cursor||(n.dataset.cursor=e)})})}_bindMouse(){document.addEventListener("mousemove",e=>{const n=e.clientX,t=e.clientY;this.cursorEl.style.left=n+"px",this.cursorEl.style.top=t+"px",this.debugEl&&(this.debugEl.style.left=n+"px",this.debugEl.style.top=t+"px");const o=document.elementFromPoint(n,t);if(!o)return;const r=o.dataset.cursor||"default";this.debugEl&&(this.debugEl.textContent=`(${n}px , ${t}px) ${r}`),r!==this.lastCursorType&&(this.debugEl?this.cursorEl.className=`cursor-${r} cursor-debugmode`:this.cursorEl.className=`cursor-${r}`,this.lastCursorType=r)})}_getMaxZIndex(){return 2147483646}}});
package/package.json CHANGED
@@ -1,13 +1,18 @@
1
1
  {
2
2
  "name": "anime-cursor",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "A lightweight JS for website animated cursors",
5
5
  "main": "dist/anime-cursor.umd.js",
6
6
  "module": "dist/anime-cursor.esm.js",
7
7
  "files": [
8
8
  "dist"
9
9
  ],
10
- "keywords": ["cursor", "animation", "ui", "javascript"],
10
+ "keywords": [
11
+ "cursor",
12
+ "animation",
13
+ "ui",
14
+ "javascript"
15
+ ],
11
16
  "scripts": {
12
17
  "build": "rollup -c"
13
18
  },