Nipplejs
:video_game: A virtual joystick for touch capable interfaces.
Install / Use
/learn @yoannmoinet/NipplejsREADME
A vanilla virtual joystick for touch capable interfaces
Documentation · Interactive Demos · Migration Guide
Table Of Contents <!-- #omit in toc -->
<details> <!-- #toc -->- Install
- Demo
- Usage
- Options
options.zoneoptions.coloroptions.sizeoptions.thresholdoptions.fadeTimeoptions.multitouchoptions.maxNumberOfJoysticksoptions.dataOnlyoptions.positionoptions.modeoptions.restJoystickoptions.restOpacityoptions.catchDistanceoptions.lockXoptions.lockYoptions.shapeoptions.dynamicPageoptions.follow
- API
- Events
- Contributing
Install
npm install nipplejs --save
Demo
Check out the interactive demos on the documentation website.
Usage
Import it the way you want into your project :
// CommonJS
var manager = require('nipplejs').create(options);
// AMD
define(['nipplejs'], function (nipplejs) {
var manager = nipplejs.create(options);
});
// Module
import nipplejs from 'nipplejs';
nipplejs.create(options);
<!-- Global -->
<script src="./nipplejs.js"></script>
<script>
var manager = nipplejs.create(options);
</script>
:warning: NB :warning: Your joystick's container must have a CSS position value set (relative, absolute, or fixed). Without it, the joystick will not be positioned correctly. The library warns in the console if position: static is detected.
Options
You can configure your joystick in different ways :
var options = {
zone: Element, // active zone
color: String,
size: Integer,
threshold: Float, // before triggering a directional event
fadeTime: Integer, // transition time
multitouch: Boolean,
maxNumberOfJoysticks: Number, // when multitouch, what is too many?
dataOnly: Boolean, // no dom element whatsoever
position: Object, // preset position for 'static' mode
mode: String, // 'dynamic', 'static' or 'semi'
restJoystick: Boolean|Object, // Re-center joystick on rest state
restOpacity: Number, // opacity when not 'dynamic' and rested
lockX: Boolean, // only move on the X axis
lockY: Boolean, // only move on the Y axis
catchDistance: Number, // distance to recycle previous joystick in 'semi' mode
shape: String, // 'circle' or 'square'
dynamicPage: Boolean, // Enable if the page has dynamically visible elements
follow: Boolean, // Makes the joystick follow the thumbstick
};
All options are optional :sunglasses:.
options.zone
Defaults to 'body'
The dom element in which all your joysticks will be injected.
<div id="zone_joystick"></div>
<script type="text/javascript" src="./nipplejs.js"></script>
<script type="text/javascript">
var options = {
zone: document.getElementById('zone_joystick'),
};
var manager = nipplejs.create(options);
</script>
This zone also serve as the mouse/touch events handler.
It represents the zone where all your joysticks will be active.
options.color
Defaults to 'white'
The background of your joystick's elements. Sets the CSS background property, so any valid value works — colors, gradients, images, etc.
Can be a single string (applied to both parts) or an object with front and back keys to style the thumb and base independently.
// Simple color
color: 'rebeccapurple',
// Gradient
color: 'linear-gradient(135deg, #818cf8, #6366f1)',
// Different front (thumb) and back (base)
color: {
front: 'linear-gradient(135deg, #818cf8, #38bdf8)',
back: 'rgba(99, 102, 241, 0.12)',
},
// Background image
color: {
front: 'url(thumb.png) center/cover',
back: 'radial-gradient(circle, rgba(99,102,241,0.15) 40%, transparent)',
},
options.size
Defaults to 100
The size in pixel of the outer circle.
The inner circle is 50% of this size.
options.threshold
Defaults to 0.1
This is the strength needed to trigger a directional event.
Basically, the center is 0 and the outer is 1.
You need to at least go to 0.1 to trigger a directional event.
options.fadeTime
Defaults to 250
The time it takes for joystick to fade-out and fade-in when activated or de-activated.
options.multitouch
Defaults to false
Enable the multitouch capabilities.
If, for reasons, you need to have multiple nipples in the same zone.
Otherwise, it will only get one, and all new touches won't do a thing.
Please note that multitouch is off when in static or semi modes.
options.maxNumberOfJoysticks
Defaults to 1
If you need to, you can also control the maximum number of instances that could be created.
Obviously in a multitouch configuration.
options.dataOnly
Defaults to false
The library won't draw anything in the DOM and will only trigger events with data.
options.position
Defaults to
{top: 0, left: 0}
An object that will determine the position of a static mode.
You can pass any of the four top, right, bottom and left.
They will be applied as any css property.
Ex :
{top: '50px', left: '50px'}{left: '10%', bottom: '10%'}
options.mode
Defaults to 'dynamic'.
Three modes are possible :
'dynamic'
- a new joystick is created at each new touch.
- the joystick gets destroyed when released.
- can be multitouch.
'semi'
- new joystick is created at each new touch farther than
options.catchDistanceof any previously created joystick. - the joystick is faded-out when released but not destroyed.
- when touch is made inside the
options.catchDistancea new direction is triggered immediately. - when touch is made outside the
options.catchDistancethe previous joystick is destroyed and a new one is created. - cannot be multitouch.
'static'
- a joystick is positioned immediately at
options.position. - one joystick per zone.
- each new touch triggers a new direction.
- cannot be multitouch.
options.restJoystick
Defaults to true
Reset the joystick's position when it enters the rest state.
You can pass a boolean value to reset the joystick's position for both the axis.
var joystick = nipplejs.create({
restJoystick: true,
// This is converted to {x: true, y: true}
// OR
restJoystick: false,
// This is converted to {x: false, y: false}
});
Or you can pass an object to specify which axis should be reset.
var joystick = nipplejs.create({
restJoystick: {x: false},
// This is converted to {x: false, y: true}
// OR
restJoystick: {x: false, y: true},
});
options.restOpacity
Defaults to 0.5
The opacity to apply when the joystick is in a rest position.
options.catchDistance
Defaults to 200
This is only useful in the semi mode, and determine at which distance we recycle the previous joystick.
At 200 (px), if you press the zone into a rayon of 200px around the previously displayed joystick,
it will act as a static one.
options.lockX
Defaults to false
Locks joystick's movement to the x (horizontal) axis
options.lockY
Defaults to false
Locks joystick's movement to the y (vertical) axis
options.shape
Defaults to 'circle'
The shape of region within which joystick can move.
'circle'
Creates circle region for joystick movement
'square'
Creates square region for joystick movement
options.dynamicPage
Defaults to false
Nuclear option: forces a recalculation of the joystick position on every single move event. This has a notable performance cost.
In most cases you don't need this — the zone is automatically watched with a ResizeObserver that handles size changes. For one-off layout changes (e.g. entering fullscreen, opening a sidebar), call manager.reposition() instead.
Related Skills
docs-writer
99.1k`docs-writer` skill instructions As an expert technical writer and editor for the Gemini CLI project, you produce accurate, clear, and consistent documentation. When asked to write, edit, or revie
model-usage
336.5kUse CodexBar CLI local cost usage to summarize per-model usage for Codex or Claude, including the current (most recent) model or a full model breakdown. Trigger when asked for model-level usage/cost data from codexbar, or when you need a scriptable per-model summary from codexbar cost JSON.
arscontexta
2.9kClaude Code plugin that generates individualized knowledge systems from conversation. You describe how you think and work, have a conversation and get a complete second brain as markdown files you own.
cursor-agent-tracking
134A repository that provides a structured system for maintaining context and tracking changes in Cursor's AGENT mode conversations through template files, enabling better continuity and organization of AI interactions.
