{"id":13797878,"url":"https://github.com/CoughDrop/gazelinger","last_synced_at":"2025-05-13T04:32:30.869Z","repository":{"id":137795888,"uuid":"52393205","full_name":"CoughDrop/gazelinger","owner":"CoughDrop","description":"Listen for gaze events from common eye tracking libraries","archived":false,"fork":false,"pushed_at":"2021-02-12T18:51:13.000Z","size":34,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-18T12:46:46.965Z","etag":null,"topics":["aac","disabilities","eye-tracker","html5"],"latest_commit_sha":null,"homepage":null,"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/CoughDrop.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-02-23T21:33:29.000Z","updated_at":"2021-02-12T18:51:15.000Z","dependencies_parsed_at":"2023-05-22T14:15:16.869Z","dependency_job_id":null,"html_url":"https://github.com/CoughDrop/gazelinger","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CoughDrop%2Fgazelinger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CoughDrop%2Fgazelinger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CoughDrop%2Fgazelinger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CoughDrop%2Fgazelinger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CoughDrop","download_url":"https://codeload.github.com/CoughDrop/gazelinger/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253877044,"owners_count":21977629,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["aac","disabilities","eye-tracker","html5"],"created_at":"2024-08-04T00:00:35.597Z","updated_at":"2025-05-13T04:32:30.272Z","avatar_url":"https://github.com/CoughDrop.png","language":"JavaScript","funding_links":[],"categories":["Eyegaze"],"sub_categories":[],"readme":"## Gaze-linger\r\n\r\nGaze-linger is a node module created to support the CoughDrop Electron app, but it should\r\nwork in other node settings as well. Basically Gaze-linger listens for eye gaze events\r\nfrom the eye-tracking libraries that we have also built modules for. When events come in,\r\nit averages them out and uses them to create \"linger\" events, which are slices of time\r\nwhere the eye lingers momentarily (say, 200ms) on the same point. These events can be\r\npassed to a listener for more handling.\r\n\r\nGaze-linger also comes with a listener script `electron-listener.js` which can be run within the app window\r\nin an Electron app. This listener script resolves any differences in screen ratio between\r\nthe native client and the browser, finds the element underneath the linger, and triggers\r\na `gazelinger` event.\r\n\r\n### Installation and Usage\r\n\r\n```bash\r\n# install gazelinger\r\nnpm install https://github.com/coughdrop/gazelinger.git\r\n\r\n# install any compatible eye tracking libraries you want to use\r\nnpm install https://github.com/coughdrop/eyex.git\r\nnpm install https://github.com/coughdrop/eyetribe.git\r\n```\r\n\r\n```\r\nvar gazelinger = require('gazelinger');\r\n\r\ngazelinger.listen(function(data) {\r\n  console.log(data);\r\n});\r\n\r\ngazelinger.stop_listening();\r\n```\r\n\r\n\r\n### Technical Notes\r\n\r\nWithout any of the related eye tracking libraries ([coughdrop/eyex](https://github.com/coughdrop/eyex), \r\n[coughdrop/eyetribe](https://github.com/coughdrop/eyetribe), etc.)\r\nthis won't do much since it doesn't do anything on its own. When a supported eye tracker library\r\nis installed and an eye tracker is present, gazelinger polls for eye events and returns them\r\nto the specified callback.\r\n\r\n#### Averaging algorithm\r\n- Sample every 50ms\r\n- Prune any samples more than 200ms in the past\r\n- Compute the median of the remaining samples\r\n- Remove any samples more than 50px away from the median\r\n- If there are no gaps larger then 50ms between the remaining samples, consider it a valid linger\r\n\r\n#### Handling linger visualizations\r\nYou're probably going to want some kind of visualization to appear on-screen identifying\r\nwhere the current linger event is occurring. However, since `electron-listener` is \r\ntriggering events, it's very likely that the on-screen linger icon will be on top of the\r\nactual DOM element that should be triggered. If you give your linger icon the id of \r\n`linger` then it will be properly ignored.\r\n\r\n```\r\nvar listener = require('electron-listener'); // run in electron browser process\r\n\r\nlistener.listen('noisy'); // default is 'noisy', also accepts 'averaged'\r\n\r\nlistener.stop_listening();\r\n\r\n// this element will automagically be ignored when triggering linger events\r\nvar linger = document.getElementById('linger');\r\ndocument.addEventListener('gazelinger', function(event) {\r\n  var elem = event.target;\r\n  var width = $(elem).width();\r\n  var height = $(elem).height();\r\n  elem.style.left = (event.clientX - (width / 2)) + 'px';\r\n  elem.style.top = (event.clientY - (height / 2)) + 'px';\r\n});\r\n```\r\n\r\nKeep in mind that `electron-listener` assumes it's run in the window process with jQuery included\r\n and that `gazelinger` has been required in the main process with code similar to this:\r\n\r\n```\r\nvar gazelinger = require('gazelinger');\r\nconst ipcMain = require('electron').ipcMain;\r\nvar sender = null;\r\n\r\nipcMain.on('eye-gaze-subscribe', function(event, args) {\r\n  sender = event.sender;\r\n  gazelinger.listen(function(data, args[0]) {\r\n    if(sender) {\r\n      sender.send('eye-gaze-data', JSON.stringify(data));\r\n    }\r\n  });\r\n});\r\n\r\nipcMain.on('eye-gaze-unsubscribe', function(event, args) {\r\n  sender = null;\r\n  gazelinger.stop_listening();\r\n});\r\n```\r\n\r\n#### Gotchas\r\n\r\nThe Eyegaze Edge library does not account for pixel density ratios. I haven't found a clean\r\nway to correct for this other than to check for it client-side. So when you get a message\r\nback from gazelinger, make sure to check the `scaled` attribute. If it's explicitly set to\r\nfalse then the coordinates will not match the coordinates from other libraries unless you\r\nmultiple by `window.devicePixelRatio`.\r\n\r\n\r\n### License\r\n\r\nMIT\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCoughDrop%2Fgazelinger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FCoughDrop%2Fgazelinger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCoughDrop%2Fgazelinger/lists"}