{"id":13438812,"url":"https://github.com/yoannmoinet/nipplejs","last_synced_at":"2026-05-11T21:01:12.326Z","repository":{"id":39561917,"uuid":"41976858","full_name":"yoannmoinet/nipplejs","owner":"yoannmoinet","description":":video_game: A virtual joystick for touch capable interfaces.","archived":false,"fork":false,"pushed_at":"2026-05-11T19:11:11.000Z","size":188001,"stargazers_count":1922,"open_issues_count":39,"forks_count":197,"subscribers_count":26,"default_branch":"master","last_synced_at":"2026-05-11T20:37:59.234Z","etag":null,"topics":["dependency-free","dom","frontend","gamedev","joystick","vanilla-javascript"],"latest_commit_sha":null,"homepage":"https://yoannmoi.net/nipplejs/","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/yoannmoinet.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2015-09-05T21:55:09.000Z","updated_at":"2026-05-11T19:00:34.000Z","dependencies_parsed_at":"2023-02-01T07:16:10.147Z","dependency_job_id":"0e1442f5-3833-4019-9e4e-d0651b17bb64","html_url":"https://github.com/yoannmoinet/nipplejs","commit_stats":{"total_commits":361,"total_committers":28,"mean_commits":"12.892857142857142","dds":0.2991689750692521,"last_synced_commit":"8e02373300b152a3cf0f745b911fa40be30a9a58"},"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"purl":"pkg:github/yoannmoinet/nipplejs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoannmoinet%2Fnipplejs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoannmoinet%2Fnipplejs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoannmoinet%2Fnipplejs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoannmoinet%2Fnipplejs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yoannmoinet","download_url":"https://codeload.github.com/yoannmoinet/nipplejs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoannmoinet%2Fnipplejs/sbom","scorecard":{"id":1244987,"data":{"date":"2026-03-09","repo":{"name":"github.com/yoannmoinet/nipplejs","commit":"9fca6e72bb99318d69092075015140179f4e32bf"},"scorecard":{"version":"v5.4.1-0.20260302234127-4dbf14294ff1","commit":"4dbf14294ff1c660e93a2c6b70159f8f9b7e1051"},"score":2.9,"checks":[{"name":"Code-Review","score":3,"reason":"Found 6/18 approved changesets -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/4dbf14294ff1c660e93a2c6b70159f8f9b7e1051/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/4dbf14294ff1c660e93a2c6b70159f8f9b7e1051/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/4dbf14294ff1c660e93a2c6b70159f8f9b7e1051/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/4dbf14294ff1c660e93a2c6b70159f8f9b7e1051/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/4dbf14294ff1c660e93a2c6b70159f8f9b7e1051/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/4dbf14294ff1c660e93a2c6b70159f8f9b7e1051/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/4dbf14294ff1c660e93a2c6b70159f8f9b7e1051/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/4dbf14294ff1c660e93a2c6b70159f8f9b7e1051/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/4dbf14294ff1c660e93a2c6b70159f8f9b7e1051/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/4dbf14294ff1c660e93a2c6b70159f8f9b7e1051/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/4dbf14294ff1c660e93a2c6b70159f8f9b7e1051/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/4dbf14294ff1c660e93a2c6b70159f8f9b7e1051/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/4dbf14294ff1c660e93a2c6b70159f8f9b7e1051/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 18 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/4dbf14294ff1c660e93a2c6b70159f8f9b7e1051/docs/checks.md#sast"}}]},"last_synced_at":"2026-03-18T10:57:18.984Z","repository_id":39561917,"created_at":"2026-03-18T10:57:18.984Z","updated_at":"2026-03-18T10:57:18.984Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32912661,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-11T17:09:15.040Z","status":"ssl_error","status_checked_at":"2026-05-11T17:08:45.420Z","response_time":120,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":["dependency-free","dom","frontend","gamedev","joystick","vanilla-javascript"],"created_at":"2024-07-31T03:01:08.638Z","updated_at":"2026-05-11T21:01:12.308Z","avatar_url":"https://github.com/yoannmoinet.png","language":"TypeScript","funding_links":[],"categories":["JavaScript","frontend","TypeScript"],"sub_categories":[],"readme":"![alt tag](./assets/nipplejs.png)\n\u003e A vanilla virtual joystick for touch capable interfaces\n\n\n[![npm](https://img.shields.io/npm/v/nipplejs.svg)](https://npmjs.org/package/nipplejs)\n[![npm](https://img.shields.io/npm/dm/nipplejs.svg)](https://npmjs.org/package/nipplejs)\n\n# Table Of Contents\n\u003cdetails\u003e\n\n\u003c!-- toc --\u003e\n\n- [Install](#install)\n- [Demo](#demo)\n- [Usage](#usage)\n- [Options](#options)\n  * [`options.zone` defaults to 'body'](#optionszone-defaults-to-body)\n  * [`options.color` defaults to 'white'](#optionscolor-defaults-to-white)\n  * [`options.size` defaults to 100](#optionssize-defaults-to-100)\n  * [`options.threshold` defaults to 0.1](#optionsthreshold-defaults-to-01)\n  * [`options.fadeTime` defaults to 250](#optionsfadetime-defaults-to-250)\n  * [`options.multitouch` defaults to false](#optionsmultitouch-defaults-to-false)\n  * [`options.maxNumberOfNipples` defaults to 1](#optionsmaxnumberofnipples-defaults-to-1)\n  * [`options.dataOnly` defaults to false](#optionsdataonly-defaults-to-false)\n  * [`options.position` defaults to `{top: 0, left: 0}`](#optionsposition-defaults-to-top-0-left-0)\n  * [`options.mode` defaults to 'dynamic'.](#optionsmode-defaults-to-dynamic)\n    + [`'dynamic'`](#dynamic)\n    + [`'semi'`](#semi)\n    + [`'static'`](#static)\n  * [`options.restJoystick` defaults to true](#optionsrestjoystick-defaults-to-true)\n  * [`options.restOpacity` defaults to 0.5](#optionsrestopacity-defaults-to-05)\n  * [`options.catchDistance` defaults to 200](#optionscatchdistance-defaults-to-200)\n  * [`options.lockX` defaults to false](#optionslockx-defaults-to-false)\n  * [`options.lockY` defaults to false](#optionslocky-defaults-to-false)\n  * [`options.shape` defaults to 'circle'](#optionsshape-defaults-to-circle)\n    + [`'circle'`](#circle)\n    + [`'square'`](#square)\n  * [`options.dynamicPage` defaults to false](#optionsdynamicpage-defaults-to-false)\n  * [`options.follow` defaults to false](#optionsfollow-defaults-to-false)\n- [API](#api)\n  * [NippleJS instance (manager)](#nipplejs-instance-manager)\n    + [`manager.on(type, handler)`](#managerontype-handler)\n    + [`manager.off([type, handler])`](#managerofftype-handler)\n    + [`manager.get(identifier)`](#managergetidentifier)\n    + [`manager.destroy()`](#managerdestroy)\n    + [`manager.ids`](#managerids)\n    + [`manager.id`](#managerid)\n  * [nipple instance (joystick)](#nipple-instance-joystick)\n  * [`joystick.on`, `joystick.off`](#joystickon-joystickoff)\n  * [`joystick.el`](#joystickel)\n  * [`joystick.show([cb])`](#joystickshowcb)\n  * [`joystick.hide([cb])`](#joystickhidecb)\n  * [`joystick.add()`](#joystickadd)\n  * [`joystick.remove()`](#joystickremove)\n  * [`joystick.destroy()`](#joystickdestroy)\n  * [`joystick.setPosition(cb, { x, y })`](#joysticksetpositioncb--x-y-)\n  * [`joystick.identifier`](#joystickidentifier)\n  * [`joystick.trigger(type [, data])`](#joysticktriggertype--data)\n  * [`joystick.position`](#joystickposition)\n  * [`joystick.frontPosition`](#joystickfrontposition)\n  * [`joystick.ui`](#joystickui)\n- [Events](#events)\n  * [manager only](#manager-only)\n    + [`added`](#added)\n    + [`removed`](#removed)\n  * [manager and joysticks](#manager-and-joysticks)\n    + [`start`](#start)\n    + [`end`](#end)\n    + [`move`](#move)\n    + [`dir`](#dir)\n    + [`plain`](#plain)\n    + [`shown`](#shown)\n    + [`hidden`](#hidden)\n    + [`destroyed`](#destroyed)\n    + [`pressure`](#pressure)\n- [Contributing](#contributing)\n\n\u003c!-- tocstop --\u003e\n\n\u003c/details\u003e\n\n## Install\n\n```bash\nnpm install nipplejs --save\n```\n\n----\n\n## Demo\nCheck out the [demo here](http://yoannmoinet.github.io/nipplejs/#demo).\n\n----\n\n## Usage\n\nImport it the way you want into your project :\n\n```javascript\n// CommonJS\nvar manager = require('nipplejs').create(options);\n```\n\n```javascript\n// AMD\ndefine(['nipplejs'], function (nipplejs) {\n    var manager = nipplejs.create(options);\n});\n```\n\n```javascript\n// Module\nimport nipplejs from 'nipplejs';\n```\n\n```html\n\u003c!-- Global --\u003e\n\u003cscript src=\"./nipplejs.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n    var manager = nipplejs.create(options);\n\u003c/script\u003e\n```\n\n**:warning: NB :warning:** Your joystick's container **has** to have its CSS `position` property set, either `absolute`, `relative`, `static`, ....\n\n----\n\n## Options\nYou can configure your joystick in different ways :\n\n```javascript\nvar options = {\n    zone: Element,                  // active zone\n    color: String,\n    size: Integer,\n    threshold: Float,               // before triggering a directional event\n    fadeTime: Integer,              // transition time\n    multitouch: Boolean,\n    maxNumberOfNipples: Number,     // when multitouch, what is too many?\n    dataOnly: Boolean,              // no dom element whatsoever\n    position: Object,               // preset position for 'static' mode\n    mode: String,                   // 'dynamic', 'static' or 'semi'\n    restJoystick: Boolean|Object,   // Re-center joystick on rest state\n    restOpacity: Number,            // opacity when not 'dynamic' and rested\n    lockX: Boolean,                 // only move on the X axis\n    lockY: Boolean,                 // only move on the Y axis\n    catchDistance: Number,          // distance to recycle previous joystick in\n                                    // 'semi' mode\n    shape: String,                  // 'circle' or 'square'\n    dynamicPage: Boolean,           // Enable if the page has dynamically visible elements\n    follow: Boolean,                // Makes the joystick follow the thumbstick\n};\n```\n\nAll options are optional :sunglasses:.\n\n### `options.zone` defaults to 'body'\nThe dom element in which all your joysticks will be injected.\n\n```html\n\u003cdiv id=\"zone_joystick\"\u003e\u003c/div\u003e\n\n\u003cscript type=\"text/javascript\" src=\"./nipplejs.js\"\u003e\u003c/script\u003e\n\u003cscript type=\"text/javascript\"\u003e\n    var options = {\n        zone: document.getElementById('zone_joystick'),\n    };\n    var manager = nipplejs.create(options);\n\u003c/script\u003e\n```\n\nThis zone also serve as the mouse/touch events handler.\n\nIt represents the zone where all your joysticks will be active.\n\n### `options.color` defaults to 'white'\nThe background color of your joystick's elements.\n\nCan be any valid CSS color.\n\n### `options.size` defaults to 100\nThe size in pixel of the outer circle.\n\nThe inner circle is 50% of this size.\n\n### `options.threshold` defaults to 0.1\nThis is the strength needed to trigger a directional event.\n\nBasically, the center is 0 and the outer is 1.\n\nYou need to at least go to 0.1 to trigger a directional event.\n\n### `options.fadeTime` defaults to 250\nThe time it takes for joystick to fade-out and fade-in when activated or de-activated.\n\n### `options.multitouch` defaults to false\nEnable the multitouch capabilities.\n\nIf, for reasons, you need to have multiple nipples in the same zone.\n\nOtherwise, it will only get one, and all new touches won't do a thing.\n\nPlease note that multitouch is off when in `static` or `semi` modes.\n\n### `options.maxNumberOfNipples` defaults to 1\nIf you need to, you can also control the maximum number of instances that could be created.\n\nObviously in a multitouch configuration.\n\n### `options.dataOnly` defaults to false\nThe library won't draw anything in the DOM and will only trigger events with data.\n\n### `options.position` defaults to `{top: 0, left: 0}`\nAn object that will determine the position of a `static` mode.\n\nYou can pass any of the four `top`, `right`, `bottom` and `left`.\n\nThey will be applied as any css property.\n\nEx :\n- `{top: '50px', left: '50px'}`\n- `{left: '10%', bottom: '10%'}`\n\n### `options.mode` defaults to 'dynamic'.\nThree modes are possible :\n\n#### `'dynamic'`\n- a new joystick is created at each new touch.\n- the joystick gets destroyed when released.\n- **can** be multitouch.\n\n#### `'semi'`\n- new joystick is created at each new touch farther than `options.catchDistance` of any previously created joystick.\n- the joystick is faded-out when released but not destroyed.\n- when touch is made **inside** the `options.catchDistance` a new direction is triggered immediately.\n- when touch is made **outside** the `options.catchDistance` the previous joystick is destroyed and a new one is created.\n- **cannot** be multitouch.\n\n#### `'static'`\n- a joystick is positioned immediately at `options.position`.\n- one joystick per zone.\n- each new touch triggers a new direction.\n- **cannot** be multitouch.\n\n### `options.restJoystick` defaults to true\nReset the joystick's position when it enters the rest state.\n\nYou can pass a boolean value to reset the joystick's position for both the axis.\n```js\nvar joystick = nipplejs.create({\n    restJoystick: true,\n    // This is converted to {x: true, y: true}\n\n    // OR\n    restJoystick: false,\n    // This is converted to {x: false, y: false}\n});\n```\n\nOr you can pass an object to specify which axis should be reset.\n```js\nvar joystick = nipplejs.create({\n    restJoystick: {x: false},\n    // This is converted to {x: false, y: true}\n\n    // OR\n    restJoystick: {x: false, y: true},\n});\n```\n\n### `options.restOpacity` defaults to 0.5\nThe opacity to apply when the joystick is in a rest position.\n\n### `options.catchDistance` defaults to 200\nThis is only useful in the `semi` mode, and determine at which distance we recycle the previous joystick.\n\nAt 200 (px), if you press the zone into a rayon of 200px around the previously displayed joystick,\nit will act as a `static` one.\n\n### `options.lockX` defaults to false\nLocks joystick's movement to the x (horizontal) axis\n\n### `options.lockY` defaults to false\nLocks joystick's movement to the y (vertical) axis\n\n### `options.shape` defaults to 'circle'\nThe shape of region within which joystick can move.\n\n#### `'circle'`\nCreates circle region for joystick movement\n\n#### `'square'`\nCreates square region for joystick movement\n\n### `options.dynamicPage` defaults to false\nEnable if the page has dynamically visible elements such as for Vue, React, Angular or simply some CSS hiding or showing some DOM.\n\n### `options.follow` defaults to false\nMakes the joystick follow the thumbstick when it reaches the border.\n\n----\n\n## API\n\n### NippleJS instance (manager)\n\nYour manager has the following signature :\n\n```javascript\n{\n    on: Function,                       // handle internal event\n    off: Function,                      // un-handle internal event\n    get: Function,                      // get a specific joystick\n    destroy: Function,                  // destroy everything\n    ids: Array                          // array of assigned ids\n    id: Number                          // id of the manager\n    options: {\n        zone: Element,                  // reactive zone\n        multitouch: Boolean,\n        maxNumberOfNipples: Number,\n        mode: String,\n        position: Object,\n        catchDistance: Number,\n        size: Number,\n        threshold: Number,\n        color: String,\n        fadeTime: Number,\n        dataOnly: Boolean,\n        restJoystick: Boolean,\n        restOpacity: Number\n    }\n}\n```\n\n#### `manager.on(type, handler)`\n\nIf you wish to listen to internal events like :\n\n```javascript\nmanager.on('event#1 event#2', function (evt, data) {\n    // Do something.\n});\n```\n\nNote that you can listen to multiple events at once by separating\nthem either with a space or a comma (or both, I don't care).\n\n#### `manager.off([type, handler])`\n\nTo remove an event handler :\n\n```javascript\nmanager.off('event', handler);\n```\n\nIf you call off without arguments, all handlers will be removed.\n\nIf you don't specify the handler but just a type, all handlers for that type will be removed.\n\n#### `manager.get(identifier)`\n\nA helper to get an instance via its identifier.\n\n```javascript\n// Will return the nipple instantiated by the touch identified by 0\nmanager.get(0);\n```\n\n#### `manager.destroy()`\n\nGently remove all nipples from the DOM and unbind all events.\n\n```javascript\nmanager.destroy();\n```\n\n#### `manager.ids`\n\nThe array of nipples' ids under this manager.\n\n#### `manager.id`\n\nThe incremented id of this manager.\n\n### nipple instance (joystick)\n\nEach joystick has the following signature :\n\n```javascript\n{\n    on: Function,\n    off: Function,\n    el: Element,\n    show: Function,         // fade-in\n    hide: Function,         // fade-out\n    add: Function,          // inject into dom\n    remove: Function,       // remove from dom\n    destroy: Function,\n    setPosition: Function,\n    identifier: Number,\n    trigger: Function,\n    position: {             // position of the center\n        x: Number,\n        y: Number\n    },\n    frontPosition: {        // position of the front part\n        x: Number,\n        y: Number\n    },\n    ui: {\n        el: Element,\n        front: Element,\n        back: Element\n    },\n    options: {\n        color: String,\n        size: Number,\n        threshold: Number,\n        fadeTime: Number\n    }\n}\n```\n\n### `joystick.on`, `joystick.off`\n\nThe same as the manager.\n\n### `joystick.el`\n\nDom element in which the joystick gets created.\n\n```html\n\u003cdiv class=\"nipple\"\u003e\n    \u003cdiv class=\"front\"\u003e\u003c/div\u003e\n    \u003cdiv class=\"back\"\u003e\u003c/div\u003e\n\u003c/div\u003e\n```\n\n### `joystick.show([cb])`\n\nWill show the joystick at the last known place.\n\nYou can pass a callback that will be executed at the end of the fade-in animation.\n\n### `joystick.hide([cb])`\n\nWill fade-out the joystick.\n\nYou can pass a callback that will be executed at the end of the fade-out animation.\n\n### `joystick.add()`\n\nAdd the joystick's element to the dom.\n\n### `joystick.remove()`\n\nRemove the joystick's element from the dom.\n\n### `joystick.destroy()`\n\nGently remove this nipple from the DOM and unbind all related events.\n\n### `joystick.setPosition(cb, { x, y })`\n\nSet the joystick to the specified position, where x and y are distances away from the center in pixels. This does not trigger joystick events.\n\n### `joystick.identifier`\n\nReturns the unique identifier of the joystick.\n\nTied to its touch's identifier.\n\n### `joystick.trigger(type [, data])`\n\nTrigger an internal event from the joystick.\n\nThe same as `on` you can trigger multiple events at the same time.\n\n### `joystick.position`\n\nThe absolute position of the center of the joystick.\n\n### `joystick.frontPosition`\n\nThe absolute position of the back part of the joystick's ui.\n\n### `joystick.ui`\n\nThe object that store its ui elements\n\n```html\n{\n    el: \u003cdiv class=\"nipple\"\u003e\u003c/div\u003e\n    back: \u003cdiv class=\"back\"\u003e\u003c/div\u003e\n    front: \u003cdiv class=\"front\"\u003e\u003c/div\u003e\n}\n```\n\n----\n\n## Events\n\nYou can listen events both on the manager and all the joysticks.\n\nBut some of them are specific to its instance.\n\nIf you need to listen to each joystick, for example, you can :\n\n```javascript\nmanager.on('added', function (evt, nipple) {\n    nipple.on('start move end dir plain', function (evt) {\n        // DO EVERYTHING\n    });\n}).on('removed', function (evt, nipple) {\n    nipple.off('start move end dir plain');\n});\n```\n\n### manager only\n\n#### `added`\n\nA joystick just got added.\n\nWill pass the instance alongside the event.\n\n#### `removed`\n\nA joystick just got removed.\n\nFired at the end of the fade-out animation.\n\nWill pass the instance alongside the event.\n\nWon't be trigger in a `dataOnly` configuration.\n\n### manager and joysticks\n\nOther events are available on both the manager and joysticks.\n\nWhen listening on the manager,\nyou can also target **a joystick in particular** by prefixing\nthe event with its identifier, **`0:start`** for example.\n\nElse you'll get all events from all the joysticks.\n\n#### `start`\n\nA joystick is activated. (the user pressed on the active zone)\n\nWill pass the instance alongside the event.\n\n#### `end`\n\nA joystick is de-activated. (the user released the active zone)\n\nWill pass the instance alongside the event.\n\n#### `move`\n\nA joystick is moved.\n\nComes with data :\n\n```javascript\n{\n    identifier: 0,              // the identifier of the touch/mouse that triggered it\n    position: {                 // absolute position of the center in pixels\n        x: 125,\n        y: 95\n    },\n    force: 0.2,                 // strength in %\n    distance: 25.4,             // distance from center in pixels\n    pressure: 0.1,              // the pressure applied by the touch\n    angle: {\n        radian: 1.5707963268,   // angle in radian\n        degree: 90\n    },\n    vector: {                   // force unit vector\n      x: 0.508,\n      y: 3.110602869834277e-17\n    },\n    raw: {                      // note: angle is the same, beyond the 50 pixel limit\n        distance: 25.4,         // distance which continues beyond the 50 pixel limit\n        position: {             // position of the finger/mouse in pixels, beyond joystick limits\n            x: 125,\n            y: 95\n        }\n    },\n    instance: Nipple            // the nipple instance that triggered the event\n}\n```\n\n#### `dir`\n\nWhen a direction is reached after the threshold.\n\nDirection are split with a 45° angle.\n\n```javascript\n//     \\  UP /\n//      \\   /\n// LEFT       RIGHT\n//      /   \\\n//     /DOWN \\\n```\n\nYou can also listen to specific direction like :\n\n- `dir:up`\n- `dir:down`\n- `dir:right`\n- `dir:left`\n\nIn this configuration only one direction is triggered at a time.\n\n#### `plain`\n\nWhen a plain direction is reached after the threshold.\n\nPlain directions are split with a 90° angle.\n\n```javascript\n//       UP               |\n//     ------        LEFT | RIGHT\n//      DOWN              |\n```\n\nYou can also listen to specific plain direction like :\n\n- `plain:up`\n- `plain:down`\n- `plain:right`\n- `plain:left`\n\nIn this configuration two directions can be triggered at a time,\nbecause the user could be both `up` and `left` for example.\n\n#### `shown`\n\nIs triggered at the end of the fade-in animation.\n\nWill pass the instance alongside the event.\n\nWon't be trigger in a `dataOnly` configuration.\n\n#### `hidden`\n\nIs triggered at the end of the fade-out animation.\n\nWill pass the instance alongside the event.\n\nWon't be trigger in a `dataOnly` configuration.\n\n#### `destroyed`\n\nIs triggered at the end of destroy.\n\nWill pass the instance alongside the event.\n\n#### `pressure`\n\n\u003e MBP's [**Force Touch**](http://www.apple.com/macbook-pro/features-retina/#interact), iOS's [**3D Touch**](http://www.apple.com/iphone-6s/3d-touch/), Microsoft's [**pressure**](https://msdn.microsoft.com/en-us/library/hh772360%28v=vs.85%29.aspx) or MDN's [**force**](https://developer.mozilla.org/en-US/docs/Web/API/Touch/force)\n\nIs triggered when the pressure on the joystick is changed.\n\nThe value, between 0 and 1, is sent back alongside the event.\n\n----\n\n## Contributing\nYou can follow [this document](./CONTRIBUTING.md) to help you get started.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoannmoinet%2Fnipplejs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyoannmoinet%2Fnipplejs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoannmoinet%2Fnipplejs/lists"}