{"id":51452148,"url":"https://github.com/andreasnicolaou/halo-cursor","last_synced_at":"2026-07-05T22:00:55.443Z","repository":{"id":367420546,"uuid":"1180911938","full_name":"andreasnicolaou/halo-cursor","owner":"andreasnicolaou","description":"Framework-agnostic animated cursor for Angular, React, Vue, and plain TypeScript apps.","archived":false,"fork":false,"pushed_at":"2026-06-25T22:56:02.000Z","size":179,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-26T00:13:33.816Z","etag":null,"topics":["angular","animated-cursor","cursor","cursor-effects","custom-cursor","esm","framework-agnostic","halo-cursor","javascript","react","svelte","typescript","umd","vue"],"latest_commit_sha":null,"homepage":"https://andreasnicolaou.github.io/halo-cursor/","language":"TypeScript","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/andreasnicolaou.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":".github/CODEOWNERS","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-03-13T14:45:12.000Z","updated_at":"2026-06-25T22:56:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/andreasnicolaou/halo-cursor","commit_stats":null,"previous_names":["andreasnicolaou/halo-cursor"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/andreasnicolaou/halo-cursor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreasnicolaou%2Fhalo-cursor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreasnicolaou%2Fhalo-cursor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreasnicolaou%2Fhalo-cursor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreasnicolaou%2Fhalo-cursor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andreasnicolaou","download_url":"https://codeload.github.com/andreasnicolaou/halo-cursor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreasnicolaou%2Fhalo-cursor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35170542,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-05T02:00:06.290Z","response_time":100,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["angular","animated-cursor","cursor","cursor-effects","custom-cursor","esm","framework-agnostic","halo-cursor","javascript","react","svelte","typescript","umd","vue"],"created_at":"2026-07-05T22:00:54.540Z","updated_at":"2026-07-05T22:00:55.433Z","avatar_url":"https://github.com/andreasnicolaou.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Halo Cursor – Framework‑Agnostic Animated Cursor\n\nHalo Cursor is a lightweight, framework‑agnostic animated cursor halo for modern web apps. It follows the pointer, highlights interactive elements, and can completely hide the native cursor – all in plain TypeScript with zero runtime dependencies. ([demo](https://andreasnicolaou.github.io/halo-cursor/))\n\nIt works great with:\n\n- Angular\n- React\n- Vue\n- Svelte\n- plain HTML / TypeScript / JavaScript\n\n---\n\n![TypeScript](https://img.shields.io/badge/TS-TypeScript-3178c6?logo=typescript\u0026logoColor=white)\n![GitHub contributors](https://img.shields.io/github/contributors/andreasnicolaou/halo-cursor)\n![GitHub License](https://img.shields.io/github/license/andreasnicolaou/halo-cursor)\n![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/andreasnicolaou/halo-cursor/build.yaml)\n![GitHub package.json version](https://img.shields.io/github/package-json/v/andreasnicolaou/halo-cursor)\n\n![ESLint](https://img.shields.io/badge/linter-eslint-4B32C3.svg?logo=eslint)\n![Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?logo=prettier)\n![Jest](https://img.shields.io/badge/tested_with-jest-99424f.svg?logo=jest)\n![Maintenance](https://img.shields.io/maintenance/yes/2026)\n![NPM Downloads](https://img.shields.io/npm/dm/%40andreasnicolaou%2Fhalo-cursor)\n\n## Key Features\n\n- **Framework‑agnostic** – Works in any app that can run JavaScript in the browser\n- **Animated halo** – Smooth lerped motion with inner dot + outer halo\n- **Interactive‑aware** – Highlights buttons/links and other interactive elements\n- **Motion‑safe** – Respects `prefers-reduced-motion` and coarse pointers (e.g. touch)\n- **Cursor control** – Optional full native cursor hiding with `hideNativeCursor`\n- **Scoped \u0026 controllable** – Scope to a container with `rootElement`, and use `pause` / `resume`\n- **Tiny \u0026 dependency‑free** – Just one class and sensible defaults\n\n## Installation\n\n```sh\n# npm\nnpm install @andreasnicolaou/halo-cursor\n\n# yarn\nyarn add @andreasnicolaou/halo-cursor\n\n# pnpm\npnpm add @andreasnicolaou/halo-cursor\n```\n\n### CDN / Direct Usage (UMD)\n\n```html\n\u003c!-- unpkg CDN (latest version, unminified) --\u003e\n\u003cscript src=\"https://unpkg.com/@andreasnicolaou/halo-cursor/dist/index.umd.js\"\u003e\u003c/script\u003e\n\n\u003c!-- unpkg CDN (latest version, minified) --\u003e\n\u003cscript src=\"https://unpkg.com/@andreasnicolaou/halo-cursor/dist/index.umd.min.js\"\u003e\u003c/script\u003e\n\n\u003c!-- jsDelivr CDN (unminified) --\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/@andreasnicolaou/halo-cursor/dist/index.umd.js\"\u003e\u003c/script\u003e\n\n\u003c!-- jsDelivr CDN (minified) --\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/@andreasnicolaou/halo-cursor/dist/index.umd.min.js\"\u003e\u003c/script\u003e\n```\n\n**UMD (global `halo` variable):**\n\n```html\n\u003cscript src=\"https://unpkg.com/@andreasnicolaou/halo-cursor/dist/index.umd.min.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  // window.halo is the UMD global\n  const cursor = new halo.Cursor({\n    hideNativeCursor: true,\n  });\n\n  cursor.mount();\n\n  // later: cursor.destroy();\n\u003c/script\u003e\n```\n\n### ESM (recommended for bundlers)\n\n```ts\nimport { Cursor } from '@andreasnicolaou/halo-cursor';\n\nconst cursor = new Cursor({\n  outerSize: 40,\n  innerSize: 8,\n  hideNativeCursor: true,\n});\n\ncursor.mount();\n```\n\n### CJS (Node / CommonJS)\n\n```js\nconst { Cursor } = require('@andreasnicolaou/halo-cursor');\n\nconst cursor = new Cursor({\n  hideNativeCursor: true,\n});\n\ncursor.mount();\n```\n\n## Quick Usage Example\n\n```ts\nimport { Cursor } from '@andreasnicolaou/halo-cursor';\n\nconst cursor = new Cursor({\n  color: '#6366f1',\n  hoverColor: '#818cf8',\n  outerSize: 36,\n  hoverOuterSize: 52,\n  hideNativeCursor: true,\n  lerp: 0.12,\n});\n\n// Attach to the whole document\ncursor.mount();\n\n// Temporarily pause animation/interaction (e.g. while a modal is open)\ncursor.pause();\ncursor.resume();\n\n// Clean up when leaving the page / unmounting your app\n// cursor.destroy();\n```\n\n## API\n\n### `Cursor` methods\n\n| Method                   | Description                                                                                |\n| ------------------------ | ------------------------------------------------------------------------------------------ |\n| `new Cursor(options?)`   | Creates a new halo cursor instance with the given options.                                 |\n| `mount()`                | Injects styles, creates DOM elements, attaches events, and starts the animation loop.      |\n| `destroy()`              | Stops the loop, removes event listeners, DOM nodes, and restores the native cursor.        |\n| `updateOptions(options)` | Merges new options into the existing ones and reinjects the stylesheet while mounted.      |\n| `pause()`                | Temporarily pauses tracking and hides the halo off‑screen without destroying the instance. |\n| `resume()`               | Resumes tracking and animation after a previous `pause()`.                                 |\n\n### `CursorOptions`\n\n| Property                 | Type                  | Default                                                                        | Description                                                                                       |\n| ------------------------ | --------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- |\n| `outerSize`              | `number`              | `36`                                                                           | Size of the outer halo ring in pixels                                                             |\n| `innerSize`              | `number`              | `6`                                                                            | Size of the inner dot in pixels                                                                   |\n| `hoverOuterSize`         | `number`              | `52`                                                                           | Outer ring size on hover                                                                          |\n| `clickOuterSize`         | `number`              | `26`                                                                           | Outer ring size on click                                                                          |\n| `color`                  | `string`              | `'#6366f1'`                                                                    | Base color of the cursor halo                                                                     |\n| `hoverColor`             | `string`              | `'#818cf8'`                                                                    | Color on hover state                                                                              |\n| `outerBorderColor`       | `string`              | `'rgba(99, 102, 241, 0.7)'`                                                    | Outer ring border color                                                                           |\n| `hoverBorderColor`       | `string`              | `'rgba(129, 140, 248, 1)'`                                                     | Outer ring border color on hover                                                                  |\n| `outerBackground`        | `string`              | `'transparent'`                                                                | Outer ring background fill                                                                        |\n| `hoverBackground`        | `string`              | `'rgba(99, 102, 241, 0.08)'`                                                   | Background fill on hover                                                                          |\n| `clickBackground`        | `string`              | `'rgba(99, 102, 241, 0.18)'`                                                   | Background fill on click                                                                          |\n| `zIndex`                 | `number`              | `9999`                                                                         | CSS z-index for cursor elements                                                                   |\n| `lerp`                   | `number`              | `0.12`                                                                         | Smoothing factor for cursor movement (0–1, clamped). Higher = snappier, lower = smoother/more lag |\n| `hideNativeCursor`       | `boolean`             | `true`                                                                         | Hide the native browser cursor                                                                    |\n| `interactiveSelectors`   | `string`              | `'a, button, [role=\"button\"], input, textarea, select, label, [tabindex=\"0\"]'` | CSS selectors for interactive elements                                                            |\n| `classPrefix`            | `string`              | `'halo-cursor'`                                                                | CSS class name prefix for generated elements                                                      |\n| `disableOnReducedMotion` | `boolean`             | `true`                                                                         | Disable animations if reduced motion is preferred                                                 |\n| `rootElement`            | `HTMLElement \\| null` | `null`                                                                         | Root element to mount cursor into                                                                 |\n\n## Framework Examples\n\n### Angular\n\n```ts\nimport { AfterViewInit, Component, ElementRef, OnDestroy, ViewChild } from '@angular/core';\nimport { Cursor } from '@andreasnicolaou/halo-cursor';\n\n@Component({\n  selector: 'app-root',\n  template: ` \u003cdiv #scope class=\"app-shell\"\u003e\u003cng-content\u003e\u003c/ng-content\u003e\u003c/div\u003e `,\n})\nexport class AppComponent implements AfterViewInit, OnDestroy {\n  @ViewChild('scope', { static: true }) scopeRef!: ElementRef\u003cHTMLDivElement\u003e;\n\n  private cursor: Cursor | null = null;\n\n  ngAfterViewInit(): void {\n    this.cursor = new Cursor({ rootElement: this.scopeRef.nativeElement, hideNativeCursor: true });\n    this.cursor.mount();\n  }\n\n  ngOnDestroy(): void {\n    this.cursor?.destroy();\n  }\n}\n```\n\n### React\n\n```tsx\nimport { useEffect, useRef } from 'react';\nimport { Cursor } from '@andreasnicolaou/halo-cursor';\n\nexport function AppCursorScope() {\n  const ref = useRef\u003cHTMLDivElement | null\u003e(null);\n\n  useEffect(() =\u003e {\n    if (!ref.current) return;\n\n    const cursor = new Cursor({ rootElement: ref.current, hideNativeCursor: true });\n    cursor.mount();\n\n    return () =\u003e cursor.destroy();\n  }, []);\n\n  return \u003cdiv ref={ref}\u003e{/* your app */}\u003c/div\u003e;\n}\n```\n\n### Vue\n\n```ts\nimport { onBeforeUnmount, onMounted, ref } from 'vue';\nimport { Cursor } from '@andreasnicolaou/halo-cursor';\n\nconst scopeRef = ref\u003cHTMLElement | null\u003e(null);\nlet cursor: Cursor | null = null;\n\nonMounted(() =\u003e {\n  if (!scopeRef.value) return;\n  cursor = new Cursor({ rootElement: scopeRef.value, hideNativeCursor: true });\n  cursor.mount();\n});\n\nonBeforeUnmount(() =\u003e {\n  cursor?.destroy();\n});\n```\n\nUse in your template:\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv ref=\"scopeRef\"\u003e\n    \u003c!-- your content --\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n```\n\n## Notes \u0026 Accessibility\n\n- The cursor **auto‑disables** itself on coarse pointers (e.g. touch devices).\n- When `disableOnReducedMotion` is `true` (default), it also **disables itself** when `prefers-reduced-motion: reduce` is enabled.\n- All DOM access happens inside `mount()` / `destroy()`, keeping the class safe to instantiate in SSR environments.\n\n---\n\n## Contributing\n\nContributions, ideas, and bug reports are welcome. Feel free to open an issue or PR on the GitHub repository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreasnicolaou%2Fhalo-cursor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandreasnicolaou%2Fhalo-cursor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreasnicolaou%2Fhalo-cursor/lists"}