{"id":41491250,"url":"https://github.com/shuninyu/anime-cursor","last_synced_at":"2026-04-02T13:47:48.334Z","repository":{"id":334138935,"uuid":"1140219129","full_name":"ShuninYu/anime-cursor","owner":"ShuninYu","description":"A lightweight JavaScript library for animated custom cursors","archived":false,"fork":false,"pushed_at":"2026-02-13T08:56:27.000Z","size":5682,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-13T16:28:19.367Z","etag":null,"topics":["animation","anime","css","cursor","dynamic","framebyframe","frames","gif","html","javascript","mouse","mouse-pointer","png","pointer","web","webpage","website"],"latest_commit_sha":null,"homepage":"https://animecursor.js.org/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ShuninYu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-23T01:30:06.000Z","updated_at":"2026-01-30T02:28:37.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ShuninYu/anime-cursor","commit_stats":null,"previous_names":["shuninyu/anime-cursor"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/ShuninYu/anime-cursor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ShuninYu%2Fanime-cursor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ShuninYu%2Fanime-cursor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ShuninYu%2Fanime-cursor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ShuninYu%2Fanime-cursor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ShuninYu","download_url":"https://codeload.github.com/ShuninYu/anime-cursor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ShuninYu%2Fanime-cursor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29430355,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-13T22:20:51.549Z","status":"ssl_error","status_checked_at":"2026-02-13T22:20:49.838Z","response_time":78,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["animation","anime","css","cursor","dynamic","framebyframe","frames","gif","html","javascript","mouse","mouse-pointer","png","pointer","web","webpage","website"],"created_at":"2026-01-23T18:20:59.381Z","updated_at":"2026-04-02T13:47:48.319Z","avatar_url":"https://github.com/ShuninYu.png","language":"JavaScript","readme":"# AnimeCursor v2\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://cdn.jsdelivr.net/gh/shuninyu/anime-cursor@main/title.gif\" width=\"384px\" alt=\"AnimeCursor\"/\u003e\n\u003c/div\u003e\n\n\n\n[[简体中文]](#sc)\n\n## [Visit the official website](https://shuninyu.github.io/anime-cursor/) for more informations\n\n## [Read documents](https://shuninyu.github.io/anime-cursor/docs) to get started with AnimeCursor\n\nAnimeCursor is a lightweight JavaScript library for frame-by-frame animated custom cursors.\n\nAnimeCursor has no dependencies on any frameworks, making it suitable for personal websites, creative portfolios, and experimental UI projects.\n\n---\n\n## ✨ Features\n\n* **Native CSS Cursor** – Uses the browser's native cursor, no simulated elements, high performance and accuracy.\n* **Independent Frame Images** – Supports multi-frame animations using separate image files (PNG, SVG, etc.).\n* **Smart Frame Detection** – Automatically detects numeric suffixes in image filenames (e.g., `cursor_01.png`, `cursor (02).png`, `cursor[3].png`). Just provide the first frame, and AnimeCursor will generate all frames.\n* **Variable Speed Animation** – Use arrays for `frames` and `duration` to create complex timing patterns (e.g., `frames: [2, 3], duration: [0.2, 1]` means 2 frames in 0.2s, then 3 frames in 1s).\n* **Static Cursor Support** – If `frames` or `duration` is missing or invalid, the cursor is treated as static (single image).\n* **Automatic Cursor Switching** – Define cursor styles for specific HTML tags or via `data-cursor` attributes.\n* **Lightweight \u0026 Zero Dependencies** – Built with vanilla JavaScript, no external libraries required.\n\n## 📦 Installation\n\n### CDN\n\n```html\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/anime-cursor@v2.1.2/dist/anime-cursor.umd.min.js\"\u003e\u003c/script\u003e\n```\n\n### npm\n\n```bash\nnpm i anime-cursor\n```\n\n```js\nimport AnimeCursor from 'anime-cursor';\nnew AnimeCursor({...});\n```\n\n### Host Yourself\n\n```html\n\u003cscript src=\"anime-cursor.umd.min.js\"\u003e\u003c/script\u003e\n```\n\n## 🚀 How to use\n\nHere is an example of how to use AnimeCursor:\n\n**IMPORTANT**\n\n- Ensure the initialization code is placed **within** the `\u003cbody\u003e` tag of your HTML document.\n- For optimal performance, it is recommended to initialize AnimeCursor **before** the DOM has fully loaded, as certain features require execution prior to the completion of DOM loading.\n\n```javascript\nnew AnimeCursor({\n    debug: true, // optional, shows debug overlay\n    enableTouch: false, // optional, enable on touch devices\n    fallbackCursor: 'auto', // optional, fallback cursor type\n    excludeSelectors: 'input, textarea, [contenteditable]', // optional, restore native text cursor\n    cursors: {\n        // each cursor type must have an image and frames/duration\n        idle: {\n            image: 'https://example.com/cursor_default.png', // static cursor (no animation)\n            default: true // set as default cursor\n        },\n        // variable speed animation with independent frames\n        pointer: {\n            tags: ['a', 'button'], // apply to these HTML tags\n            image: 'https://example.com/pointer_001.png', // AnimeCursor will automatically find pointer_002.png, pointer_003.png, etc.\n            frames: 4,               // total frames (uniform animation)\n            duration: 0.4,           // total duration in seconds\n            offset: [15, 25],        // hotspot offset (x, y) for url()\n            pingpong: true           // enable alternate loop\n        },\n        // array-based variable speed animation\n        custom: {\n            image: 'https://example.com/custom_01.png',\n            frames: [2, 3, 1],        // first 2 frames, then 3 frames, then 1 frame\n            duration: [0.2, 1.0, 0.5], // each segment duration\n            offset: [8, 8],\n            pingpong: false\n        },\n        // static cursor (no frames or duration)\n        text: {\n            tags: ['p', 'h1', 'h2', 'span'],\n            image: 'https://example.com/cursor_text.png'\n        }\n    }\n});\n```\n\nFor non-default cursors, if you need a specific element to trigger the cursor, manually add the `data-cursor` attribute to the element. For example: `\u003cdiv class=\"custom-div\" data-cursor=\"pointer\"\u003e\u003c/div\u003e`.\n\n## ⚙️ Configuration Options\n\n### `cursors` (Required)\n\nAn object that defines all cursor types. Each key is a cursor name (any string).\n\n#### Cursor Configuration Parameters\n\n| Parameter  | Type               | Required | Description                                                  |\n| ---------- | ------------------ | -------- | ------------------------------------------------------------ |\n| `image`    | string             | **Yes**  | URL of the first frame image. AnimeCursor will automatically detect numeric suffixes to generate subsequent frames (e.g., `image_001.png` → `image_002.png`, `image_003.png`). If you want a single static image, just provide one image. |\n| `frames`   | number \\| number[] | **Yes**  | Number of frames (for uniform animation) or an array of segment lengths (for variable speed). Total frames = sum of array elements. If not provided, the cursor is static. |\n| `duration` | number \\| number[] | **Yes**  | Total duration in seconds (for uniform) or array of segment durations (must match `frames` array length). |\n| `tags`     | string[]           | No       | HTML tag names (e.g., `['a', 'button']`) that should use this cursor. If omitted, the cursor can only be applied via `data-cursor` attribute. |\n| `offset`   | [number, number]   | No       | Hotspot offset (x, y) in pixels. Default: `[0, 0]`. The offset defines where the actual click point is relative to the top-left of the image. |\n| `pingpong` | boolean            | No       | If `true`, the animation plays forward then backward alternately. Default: `false`. |\n| `fallback` | string             | No       | Fallback cursor type (e.g., `auto`, `pointer`). Default: value of `fallbackCursor` in root options. |\n| `default`  | boolean            | No       | Set this cursor as the default cursor (used when no other cursor applies). Only one cursor can be default. |\n\n### Root Options\n\n| Option             | Type    | Default                                | Description                                                  |\n| ------------------ | ------- | -------------------------------------- | ------------------------------------------------------------ |\n| `combineAnimations` | boolean | `false` | Automatically merges cursor animations with element‑defined animations (via `data-ac-animation`). When enabled, any element with the `data-ac-animation` attribute will have its own CSS animation combined with the cursor animation, allowing both to run simultaneously without overriding each other. |\n| `debug`            | boolean | `false`                                | Enables a debug overlay showing current cursor type and coordinates. |\n| `enableTouch`      | boolean | `false`                                | Allow animated cursors on touch devices (detected automatically, disabled by default). |\n| `fallbackCursor`   | string  | `'auto'`                               | Global fallback cursor for all animated cursors (e.g., `'auto'`, `'pointer'`). |\n| `excludeSelectors` | string  | `'input, textarea, [contenteditable]'` | CSS selectors that should always use the native text cursor. |\n\n## 📝 Notes\n\n### 🖼️ Independent Frame Images\n\n- AnimeCursor expects the first frame file to contain a numeric suffix (e.g., `cursor_001.png`). It will automatically generate URLs for subsequent frames by incrementing the number while preserving formatting (leading zeros, parentheses, brackets).\n- Supported patterns:\n    - `cursor_01.png` → `cursor_02.png`, `cursor_03.png`, …\n    - `cursor(01).png` → `cursor(02).png`, `cursor(03).png`, …\n    - `cursor[1].png` → `cursor[2].png`, `cursor[3].png`, …\n    - `cursor_1.png` → `cursor_2.png`, `cursor_3.png`, … (no padding)\n    - If no number is found, the library will append `_%d` (e.g., `cursor.png` → `cursor_1.png`, `cursor_2.png`).\n- **Important**: All frames must be the same size. The actual cursor size is the natural size of the images; scale them beforehand if needed.\n\n### 🎞️ Animation Rules\n\n- **Uniform Animation**: `frames` and `duration` are both numbers. The animation cycles through all frames evenly over the total duration.\n- **Variable Speed Animation**: `frames` and `duration` are arrays of equal length. Each segment defines a number of frames and the time to play them. The frames are evenly distributed within each segment.\n- **Static Cursor**: If `frames` or `duration` is missing, or if they are invalid (e.g., non-positive numbers, mismatched array lengths), the cursor is treated as static (only the first image is used). A warning will be logged in the console.\n\n### 🎞️ Combining Animations\n\nIf your elements already have their own CSS animations (e.g., `animation: spin 2s infinite`), they may override AnimeCursor's cursor animations. To make both play together, enable the `combineAnimations` global option and add a `data-ac-animation` attribute to the element with your animation definition(s). AnimeCursor will then automatically combine them.\n\nExample:\n\n```html\n\u003cbutton data-ac-animation=\"mySpin 2s linear infinite\"\u003eClick Me\u003c/button\u003e\nnew AnimeCursor({\n    combineAnimations: true,\n    cursors: { ... }\n});\n```\nMultiple animations can be listed, separated by commas.\n\n### 🧩 Tagging Mechanism\n\nAnimeCursor automatically adds the appropriate cursor style to elements based on `tags` and `data-cursor` attributes:\n\n- If an element's tag name matches a `tags` list, the corresponding cursor will be applied.\n- You can also manually set `data-cursor=\"cursorName\"` on any element to force a specific cursor.\n- The default cursor is used when no other rule matches.\n\n### 🔧 Performance\n\nBecause v2 uses native CSS `cursor` property and CSS animations, there is no JavaScript `mousemove` listener (except when `debug` mode is enabled). This yields optimal performance and smooth cursor movement.\n\n## ❌ Error Handling\n\n- Missing required configuration will throw an error and stop initialization.\n- Invalid optional configuration (e.g., mismatched array lengths) will log a warning and treat the cursor as static.\n- All errors and warnings are prefixed with `[AnimeCursor]`.\n\n---\n\n\u003cspan id=\"sc\"\u003e\u003c/span\u003e\n# AnimeCursor v2\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://cdn.jsdelivr.net/gh/shuninyu/anime-cursor@main/title.gif\" width=\"384px\" alt=\"AnimeCursor\"/\u003e\n\u003c/div\u003e\n\n\n\n## [访问官网](https://shuninyu.github.io/anime-cursor/)以获取更多信息\n\n## [阅读文档](https://shuninyu.github.io/anime-cursor/docs/zh)快速上手 AnimeCursor\n\nAnimeCursor 是一个轻量级自定义逐帧动画光标 JavaScript 库。\n\nAnimeCursor 无需依赖任何框架，适合个人网站、创意作品集以及实验性 UI 项目。\n\n---\n\n## ✨ 特性\n\n* **原生 CSS 光标** – 使用浏览器原生光标，无需模拟元素，性能更高，定位更精准。\n* **独立帧图片支持** – 支持使用多张独立图片（PNG、SVG 等）制作逐帧动画。\n* **智能帧识别** – 自动识别文件名中的数字序号（如 `cursor_01.png`、`cursor (02).png`、`cursor[3].png`），只需提供第一帧，库会自动生成后续帧。\n* **变速动画** – `frames` 和 `duration` 可设置为数组，实现复杂的时间节奏（例如 `frames: [2, 3], duration: [0.2, 1]` 表示前 2 帧 0.2 秒，后 3 帧 1 秒）。\n* **静态光标** – 如果不设置 `frames` 或 `duration`，或设置无效，则视为静态光标（仅使用第一帧）。\n* **自动光标切换** – 通过 HTML 标签或 `data-cursor` 属性自动切换光标样式。\n* **轻量无依赖** – 原生 JavaScript 编写，不依赖任何第三方库。\n\n## 📦 部署方法\n\n### CDN\n\n```html\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/anime-cursor@v2.1.2/dist/anime-cursor.umd.min.js\"\u003e\u003c/script\u003e\n```\n\n### npm\n\n```bash\nnpm i anime-cursor\n```\n\n```js\nimport AnimeCursor from 'anime-cursor';\nnew AnimeCursor({...});\n```\n\n### 本地部署\n\n```html\n\u003cscript src=\"anime-cursor.umd.min.js\"\u003e\u003c/script\u003e\n```\n\n## 🚀 基础用法\n\n下面是一个 AnimeCursor 使用示例：\n\n**重要提示**\n\n- 请务必将初始化代码置于HTML文档的 **`\u003cbody\u003e`** 标签内部。\n- 为获得最佳性能，建议在DOM完全加载**之前**初始化AnimeCursor，因其部分功能需在DOM加载完成前执行。\n\n```javascript\nnew AnimeCursor({\n    debug: true, // 可选，显示调试浮层\n    enableTouch: false, // 可选，在触屏设备上启用\n    fallbackCursor: 'auto', // 可选，备用光标类型\n    excludeSelectors: 'input, textarea, [contenteditable]', // 可选，恢复原生文本光标\n    cursors: {\n        // 每种光标必须有 image 和 frames/duration\n        idle: {\n            image: 'https://example.com/cursor_default.png', // 静态光标（无动画）\n            default: true // 设为默认光标\n        },\n        // 变速动画 + 独立帧图片\n        pointer: {\n            tags: ['a', 'button'], // 应用到这些标签\n            image: 'https://example.com/pointer_001.png', // 自动识别后续帧\n            frames: 4,               // 总帧数（匀速动画）\n            duration: 0.4,           // 总时长（秒）\n            offset: [15, 25],        // 热点偏移 (x, y)\n            pingpong: true           // 开启乒乓循环\n        },\n        // 数组形式的变速动画\n        custom: {\n            image: 'https://example.com/custom_01.png',\n            frames: [2, 3, 1],        // 前2帧，接着3帧，最后1帧\n            duration: [0.2, 1.0, 0.5], // 对应时长\n            offset: [8, 8],\n            pingpong: false\n        },\n        // 静态光标（无 frames/duration）\n        text: {\n            tags: ['p', 'h1', 'h2', 'span'],\n            image: 'https://example.com/cursor_text.png'\n        }\n    }\n});\n```\n\n对于非默认光标，如果需要某元素触发该光标，请手动为该元素添加 `data-cursor`。例如：`\u003cdiv class=\"custom-div\" data-cursor=\"pointer\"\u003e\u003c/div\u003e`。\n\n## ⚙️ 配置项说明\n\n### `cursors`（必填）\n\n用于定义所有光标类型的对象。每一个 key 代表一种光标类型（名称可以自由定义）。\n\n#### 光标配置参数\n\n| 参数       | 类型               | 必填   | 描述                                                         |\n| ---------- | ------------------ | ------ | ------------------------------------------------------------ |\n| `image`    | string             | **是** | 第一帧图片的 URL。库会自动识别数字后缀生成后续帧（如 `image_001.png` → `image_002.png`、`image_003.png`）。如果只需要静态光标，则只需提供一张图片。 |\n| `frames`   | number \\| number[] | **是** | 帧数（匀速动画时为一个数字）或帧段数组（变速动画）。总帧数 = 数组元素之和。若不设置，则视为静态光标。 |\n| `duration` | number \\| number[] | **是** | 总时长（秒）（匀速动画）或时长数组（必须与 `frames` 数组长度一致）。 |\n| `tags`     | string[]           | 否     | HTML 标签名数组（如 `['a', 'button']`），应用该光标的标签。若不提供，则只能通过 `data-cursor` 属性应用。 |\n| `offset`   | [number, number]   | 否     | 热点偏移 (x, y)，单位像素。默认为 `[0, 0]`。偏移定义了相对于图片左上角的实际点击位置。 |\n| `pingpong` | boolean            | 否     | 若为 `true`，动画会正向播放再反向播放，循环交替。默认为 `false`。 |\n| `fallback` | string             | 否     | 备用光标类型（如 `auto`、`pointer`）。默认使用根选项中的 `fallbackCursor`。 |\n| `default`  | boolean            | 否     | 将此光标设为默认光标（当没有其他光标匹配时使用）。只能有一个光标设为 `true`。 |\n\n### 根选项\n\n| 选项               | 类型    | 默认值                                 | 描述                                                         |\n| ------------------ | ------- | -------------------------------------- | ------------------------------------------------------------ |\n| `combineAnimations` | boolean | `false` | 自动将光标动画与元素自身定义的动画（通过 `data-ac-animation`）合并。开启后，任何带有 `data-ac-animation` 属性的元素，其光标动画与用户动画会同时播放，互不覆盖。 |\n| `debug`            | boolean | `false`                                | 启用调试浮层，显示当前光标类型和坐标。                       |\n| `enableTouch`      | boolean | `false`                                | 允许在触屏设备上显示动画光标（默认自动检测并禁用）。         |\n| `fallbackCursor`   | string  | `'auto'`                               | 全局备用光标类型，用于所有动画光标（如 `'auto'`、`'pointer'`）。 |\n| `excludeSelectors` | string  | `'input, textarea, [contenteditable]'` | 始终使用原生文本光标的 CSS 选择器。                          |\n\n## 📝 注意事项\n\n### 🖼️ 独立帧图片\n\n- AnimeCursor 期望第一帧图片的文件名包含数字序号（如 `cursor_001.png`）。它会自动递增该数字并保留格式（前导零、括号、方括号等）来生成后续帧的 URL。\n- 支持的格式示例：\n    - `cursor_01.png` → `cursor_02.png`、`cursor_03.png`……\n    - `cursor(01).png` → `cursor(02).png`、`cursor(03).png`……\n    - `cursor[1].png` → `cursor[2].png`、`cursor[3].png`……\n    - `cursor_1.png` → `cursor_2.png`、`cursor_3.png`……（无前导零）\n    - 如果没有找到数字，库会自动添加 `_%d`（例如 `cursor.png` → `cursor_1.png`、`cursor_2.png`）。\n- **重要**：所有帧的图片尺寸必须相同。光标实际大小即为图片的原始尺寸，如需缩放请预先处理好图片。\n\n### 🎞️ 动画判定\n\n- **匀速动画**：`frames` 和 `duration` 均为数字。总帧数均匀分布到总时长中。\n- **变速动画**：`frames` 和 `duration` 均为等长数组。每个片段指定帧数和该片段的时长，片段内的帧均匀分布。\n- **静态光标**：如果缺少 `frames` 或 `duration`，或者设置无效（如非正数、数组长度不匹配），则光标被视为静态（仅使用第一帧图片）。控制台会输出警告。\n\n### 🎞️ 组合动画\n\n如果元素自身已经拥有 CSS 动画（例如 `animation: spin 2s infinite`），这些动画可能会覆盖 AnimeCursor 的光标动画。要让两者同时播放，请启用 `combineAnimations` 全局选项，并为元素添加 `data-ac-animation` 属性，将你的动画定义写入其中。AnimeCursor 会自动将两者组合。\n\n示例：\n\n```html\n\u003cbutton data-ac-animation=\"mySpin 2s linear infinite\"\u003e点我\u003c/button\u003e\nnew AnimeCursor({\n    combineAnimations: true,\n    cursors: { ... }\n});\n```\n多个动画可用逗号分隔。\n\n### 🧩 标记机制\n\nAnimeCursor 会根据 `tags` 和 `data-cursor` 自动应用光标样式：\n\n- 若元素标签名匹配某个 `tags`，则应用对应的光标。\n- 你也可以手动给任意元素添加 `data-cursor=\"光标名称\"` 来强制指定光标。\n- 当没有其他规则匹配时，使用默认光标。\n\n### 🔧 性能表现\n\nv2 版本使用原生 CSS `cursor` 属性和 CSS 动画，除了 `debug` 模式外，不再需要 JavaScript 监听鼠标移动。因此性能极佳，光标移动流畅。\n\n## ❌ 错误处理\n\n- 缺少必填配置会抛出错误并停止初始化。\n- 无效的可选配置（如数组长度不匹配）会输出警告并将该光标视为静态。\n- 所有错误和警告均以 `[AnimeCursor]` 前缀输出到控制台。","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshuninyu%2Fanime-cursor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshuninyu%2Fanime-cursor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshuninyu%2Fanime-cursor/lists"}