{"id":25834837,"url":"https://github.com/vndg-rdmt/cursor-engine","last_synced_at":"2026-06-08T01:01:41.702Z","repository":{"id":176670315,"uuid":"657101997","full_name":"vndg-rdmt/cursor-engine","owner":"vndg-rdmt","description":"Typescript package with missing cursor object for powerful customisation","archived":false,"fork":false,"pushed_at":"2023-08-06T15:45:12.000Z","size":37,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-10T23:02:56.438Z","etag":null,"topics":["create-custom-cursor","cursor","custom","custom-cursor","custom-pointer","frontend","javascript-cursor","js-cursor","ts-cursor","typescript-library","ui-cursor","ui-pointer","web-cursor"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vndg-rdmt.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}},"created_at":"2023-06-22T10:18:30.000Z","updated_at":"2023-08-04T17:34:06.000Z","dependencies_parsed_at":"2025-03-01T00:59:58.554Z","dependency_job_id":"bfb2a56c-57b8-45f8-aa82-c7aabc1fa138","html_url":"https://github.com/vndg-rdmt/cursor-engine","commit_stats":null,"previous_names":["belousov-daniil/user-cursor-engine","vndg-rdmt/user-cursor-engine","vndg-rdmt/cursor-engine"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/vndg-rdmt/cursor-engine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vndg-rdmt%2Fcursor-engine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vndg-rdmt%2Fcursor-engine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vndg-rdmt%2Fcursor-engine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vndg-rdmt%2Fcursor-engine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vndg-rdmt","download_url":"https://codeload.github.com/vndg-rdmt/cursor-engine/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vndg-rdmt%2Fcursor-engine/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34043822,"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-06-07T02:00:07.652Z","response_time":124,"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":["create-custom-cursor","cursor","custom","custom-cursor","custom-pointer","frontend","javascript-cursor","js-cursor","ts-cursor","typescript-library","ui-cursor","ui-pointer","web-cursor"],"created_at":"2025-03-01T00:59:51.277Z","updated_at":"2026-06-08T01:01:41.655Z","avatar_url":"https://github.com/vndg-rdmt.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003e Current stable version: 1.0.0\n\u003e Licence: Apache 2.0\n\n\n## User cursor engine\n\nThis package provides an ability to create custom cursors and attach custom events handling logic to it. It's just an 'engine', so it's pretty lightweight and fast. It may not provide you an out-of-box ability to define and use it raw, but an ability to respond to varriaty of 'missing events' in couple with dynamic cursor's UI container and so create anything accordingly to your needs.\n\nUsage\n-----\n\n#### Creating custom cursor\n```ts \n\nimport { UCECursorEngine } from \"./cursor-engine\";\n\nexport class TestCursor extends UCECursorEngine {\n    // This tag is used to defined custom attribute name,\n    // which will be gathered by the cursor\n    protected attributeTag: string = 'cursor-attr';\n\n    public constructor() {\n        super();\n        // Insert UI to the cursor, because cursor itself node\n        // is just an empty container\n        this.insertElements(customHTMLElement);\n    };\n};\n```\n\n#### Running cursor\n```ts\nconst userCursor = new TestCursor();\n\n// starts cursor rendering and turns on event responding\nuserCursor.Render();\n\n// makes visible on screen\nuserCursor.Display();\n```\n\nCursor does not have any visible styling, so to customize it's UI you need to insert element to it using method:\n\n```ts\nuserCursor.insertElements()\n```\n\n\u003e First uppercase of a cursor property/method means it's public, while lowercase - protected.\n\n`Hide()` method removes it from screen, and `Freeze()` - stops its render cycle, which means the cursor will be freezed according to it's during state on a screen.\n\nCursor gives you ability to manage custom events, linked with its life cycle, like pointer target or targeted element cursor sattribute changed.\n\nEvents fired not only when cursor moves, but something changed under the pointer. This means that it's not neccessary to move cursor to lookup for changes, it will do it under the hood, meaning more proper events handling of a moving elements for example.\n\n\nFeatures\n--------\n\n- [x] Position serialisation\n\n\u003e Cursor will stay in the same place even after reloading\n\nInterface\n----\n\n```ts\nimport { UserCursorController } from 'CursorController'\ninterface UserCursorController\n```\n\n\n#### Show cursor on a screen \n```ts\nDisplay(customMountPoint?: HTMLElement): void\n```\n@param customMountPoint change default (document.body) node to mount cursor on\n@returns void\n\n\n#### Hide cursor\n```ts\nHide(): void\n```\n@returns void\n\n\n#### Start cursor inner rendering loop\n```ts\nRender(): void\n```\nRender loop is responsible for cursor inner logic processing,\nwhich changes its state and UI.\n@returns void\n\n\n#### Stop cursor inner render loop\n```ts\nFreeze(): void\n```\nRender loop is responsible for cursor inner logic processing,\nwhich changes its state and UI.\n@returns void\n\n\n## Docs\n\n#### Set shift between real user pointer and UserCursor UI positions\n```ts\nsetShift(xDifferencePX?: number, yDifferencePX?: number): void\n```\nHow it works - for example user is holding his mouse pointer on a x: 10 and y: 20\ncoordinates. So, by default, cursor position wound be changed to x: 10 and y: 20,\nbut cursor width and height are, for example, 5px and 5px respectively. On a screen\nit wound look like cursor triggers events when it's only his left upper corner hits a html node.\n\nSo to 'fix' that, you can set xDifferencePX and yDifferencePX. In this situatuation, after\nyou set this values to 5 and 5, cursor will look proper and trigger events when its center\nhits a node.\n@param xDifferencePX difference between user real pointer on a screen and a cursor ui position for X coordinate\n@param yDifferencePX difference between user real pointer on a screen and a cursor ui position for Y coordinate\n@returns void\n\n\n#### Add elements\n```ts\nprotected insertElements(...elements: HTMLElement[]): void\n```\nInsert any elements to cursor.\n\n\n#### Mounted screen\n\nHidden layer element, which acts like a container screen\nfor cursor element and holds it within.\n\nCursor is mounted on `Display()` to this element, so it\ncan be changed statically or dynamically.\n\n```ts\nprotected cursorScreen: HTMLElement = UCEDefaultScreen\n```\n\n#### Custom cursor attribute name\n\nHTMLElement's custom attribute name, which must be\nused to make cursor interactive and\ncustomise its behaviour.\n\nThis tag name can be used whatever you want,\nengine gives you access to it and determines its changes,\nso, for example, can be used to set custom styling to cursor,\nlike css cursor do.\n\nThis approach gives to ability to hide cursor interface\nat all to interact with it, just set custom attribute\non HTMLElement, like classname or style attribute works.\n\n```ts\nprotected abstract attributeTag: string\n```\n    \n#### Get current cursor state\n\nUsed to retrive cursor's state.\n\nMethod is exposed because of overhead of attaching additional\nmethods to handle all variaty of possible events, more like when\nthey don't event used, so feel free to use it as:\n`window.addEventListener('event-type', (e) =\u003e {\n ev = cursor.dumpState();\n})`\n\nSubscribing to events within cursor interface will require\nadditional struct to contain created UCEEventHandlers and\ndeleting unsused handlers.\n\nMaybe will be solved with WeakMap in future releases, but,\ndue to possibility to use window eventlistening, which will\nbe more efficient, it's not the feature which is being worked on.\n\n```ts\nprotected readonly dumpState: () =\u003e UCEEvent\n```\n    \n#### Events\n```ts\n/**\n * Fired when attribute value of a target is changed\n */\nprotected onTagChange:     UCEEventHandler = () =\u003e undefined;\n/**\n * Fired when target which cursor is currently\n * pointing to changed.\n */\nprotected onTargetChange:  UCEEventHandler = () =\u003e undefined;\n/**\n * Fired when cursor node is being mouted to the screen.\n * Event fired after node was mounted.\n */\nprotected onCursorDisplay: UCEEventHandler = () =\u003e undefined;\n/**\n * Fired when cursor is being removed from the screen.\n * Event is fired before node is removed.\n */\nprotected onCursorRemove:  UCEEventHandler = () =\u003e undefined;\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvndg-rdmt%2Fcursor-engine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvndg-rdmt%2Fcursor-engine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvndg-rdmt%2Fcursor-engine/lists"}