{"id":20775010,"url":"https://github.com/qdot/jiggly.js","last_synced_at":"2026-04-24T13:33:17.567Z","repository":{"id":8152366,"uuid":"9572515","full_name":"qdot/jiggly.js","owner":"qdot","description":"Vibration by any means possible. Which in this case means javascript, WebVibration, and audio.","archived":false,"fork":false,"pushed_at":"2013-04-23T00:47:28.000Z","size":224,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-12-26T02:31:37.534Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://qdot.github.io/jiggly.js","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/qdot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-04-20T23:58:23.000Z","updated_at":"2024-10-06T14:36:05.000Z","dependencies_parsed_at":"2022-09-13T10:40:56.660Z","dependency_job_id":null,"html_url":"https://github.com/qdot/jiggly.js","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/qdot/jiggly.js","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qdot%2Fjiggly.js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qdot%2Fjiggly.js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qdot%2Fjiggly.js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qdot%2Fjiggly.js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/qdot","download_url":"https://codeload.github.com/qdot/jiggly.js/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qdot%2Fjiggly.js/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32225797,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-24T13:21:15.438Z","status":"ssl_error","status_checked_at":"2026-04-24T13:21:15.005Z","response_time":64,"last_error":"SSL_read: 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":[],"created_at":"2024-11-17T12:34:10.628Z","updated_at":"2026-04-24T13:33:17.545Z","avatar_url":"https://github.com/qdot.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Jiggly.js #\n\nBy Kyle Machulis \u003ckyle@nonpolynomial.com\u003e\n\nTwitter: [@qdot](http://www.twitter.com/qdot)\n\n[http://www.nonpolynomial.com](http://www.nonpolynomial.com)\n\n## Description ##\n\nJiggly.js is a javascript library all about making things jiggly.\nHowever, most times you'd think that'd mean making DOM elements\njiggly.\n\nI'm talking about physical vibration. This library has the hopes of\nbeing the first javascript library you'll want to rub yourself against\n(and will also actually be able to. Don't think I don't know how you\nfantasize about JS libraries.).\n\nThere's already the\n[The Web Vibration API](http://www.w3.org/TR/vibration/), but it only\nallows you to turn vibration on and off for certain periods of time.\nWhile that's useful for notifications in mobile apps, it's not real\nfun for other sorts of expressive haptics. Jiggly.js provides a rather\njanky, processing heavy, half working method to give you vibration\nlevels between just off and on.\n\nNot only that, there's more out there than just cell phone vibration.\nThere are certain vibrating products like the\n[OhMiBod](http://www.ohmibod.com) that react to audio to set vibration\nspeeds. Between HTML5 and WebAudio, we should be able to let most\nmajor browsers output sound that can control these toys.\n\nFinally, someday we might have access to USB and Bluetooth vibrators\nvia the WebUSB and WebBluetooth APIs. So we're futureproofing for\nthat. Yup.\n\nThe core idea of Jiggly.js is to abstract away the methods by which we\ntrigger vibrations, and provide a common API for all of these systems\nfor setting speed and relaying patterns. After configuring output\nmethods, all API calls to Jiggly.js should look and react similarly.\n\n## Requirements ##\n\nFirst off, you're going to need something to vibrate. This requires:\n\n- A Web Browser (see below for browser requirements)\n- OPTIONAL - An Android phone running ICS (for WebVibration)\n- OPTIONAL - A audio activated vibrator like the\n  [OhMiBod](http://ohmibod.com) (for Audio Vibration)\n\nIf you have both, then lucky you! You can actually run both at once.\nIf you have neither of the optional, then, uh, enjoy listening to sine\nwaves? Maybe you're into that sort of thing? (I totally am. My Raster\nNoton collection totally confirms it.)\n\n## Browser Support ##\n\n### WebVibration Core ###\n\nOn Desktop:\n\n  - Not happening in anything unless you write your own HAL access.\n    Makes one think that most people don't have vibrators on the\n    desktop computers. Why on earth would they miss out?\n\nOn Mobile:\n\n  - Firefox Mobile: Works!\n  - Android Browser: Nope\n  - Chrome for Android: Nope\n  - Safari: HAHAHAHAHAHAHA Nope and probably never will\n  - Opera: Not tested\n  - Windows Phone: Not tested\n\n### HTML5Audio Core ###\n\nUsing [Howler.js](https://github.com/goldfire/howler.js) for our audio\ncore since it supports both HTML5 and WebAudio.\n\nOn Desktop:\n\n  - Chrome: Works!\n  - Firefox: Audio looping through Firefox seems to be glitchy on both\n    OS X and linux, aurora and nightly. May still work, but not perfect.\n  - IE: Not tested\n\nOn Mobile:\n\n  - Firefox Mobile: No luck in beta. Nightly works in a rather\n    janktastic way. Lots of glitching on audio loops.\n  - Android Browser: Sometimes works? Cuts out a lot.\n  - Chrome for Android: Sound for a second, then nothing.\n  - Safari: Not tested\n  - Opera: Not tested\n  - windows Phone: Not tested\n\n## Using the Jiggly.js API ##\n\nJiggly.js only has three usable calls:\n\n- Jiggly.setOutputMode(mode) - Sets the whether we should use\n  WebVibration, Audio, both, neither, etc...\n- Jiggly.runSpeed(power, cycle duration (optional)) - Run at a certain\n  power level until called again. For WebVibration, you can also set\n  the cycle duration. Read examples and \"how it works\" for explanation\n  of cycles.\n- Jiggly.runPattern([[power, time, cycle duration], ...]) - Similar to\n  how WebVibration works, except now with power AND time as part of\n  the pattern instead of just on/off. Cycle duration can be set per\n  pattern element.\n  \n### Examples ###\n\n```javascript\nJiggly.setOutputMode(Jiggly.outputMethods.WEBVIBRATION);\nJiggly.runSpeed(80, 100);\n```\n\nThis uses the webvibration output method, with a cycle duration of\n100ms, and a duty cycle of 80%. So, 80ms on, 20ms off.\n\nFor audio, things look mostly the same.\n\n```javascript\nJiggly.setOutputMode(Jiggly.HTML5AUDIO);\nJiggly.runSpeed(80);\n```\n\nSame as before, except our duty cycle here isn't specifically a duty\ncycle (see explanation later if you care, otherwise trust me it\nworks). We also don't need a duration because aforementioned reasons\nabout later mentioned reasons. The first argument is still considered\nto be \"percentage power\", though.\n\nFinally, you can use both by AND'ing the flags.\n\n```javascript\nJiggly.setOutputMode(Jiggly.outputMethods.WEBVIBRATION | Jiggly.outputMethods.HTML5AUDIO);\nJiggly.runSpeed(80, 100);\n```\n\nFor patterns:\n\n```javascript\nJiggly.setOutputMode(Jiggly.outputMethods.WEBVIBRATION | Jiggly.outputMethods.HTML5AUDIO);\nJiggly.runPattern([80, 100, 50], [10, 50, 100], [0, 0, 0]);\n```\n\nThis runs a pattern of:\n\n- 80% power, for 100ms, with a 50ms cycle duration, then\n- 10% power, for 50ms, with a 100ms cycle duration, then\n- Turning things off, basically.\n\nThe Jiggly.js API will most likely expand/change if/when/as I give a\nshit.\n\n## Power Level Caveats ##\n\nFor anyone asking \"But that means I can only get 100 steps of power!\":\n\nYes. This is a totally unproven and very jank ass way of triggering\nvibration through a system not made to give you the guarantees you'd\nneed in timing for more steps than that.\n\nIf you're working with WebVibration, your cycle durations probably\nwon't be higher than 50ms anyways, and since we only have millisecond\nfidelity, we don't even *HAVE* 100 steps. So shut up and enjoy what\nyou get.\n\nAnd yes I realize WebAudio and the HTML5 audio core give you far more\nfidelity but really read the last sentence of the last paragraph\nagain.\n\n## How Jiggly.js Works ##\n\nThis section covers the basic theory behind the different output modes\nfor Jiggly.js. This knowledge is not required to use the library, it's\nmostly here because I like explaining things.\n\n### Janking The WebVibration API ###\n\nFirst off, we'll describe how we set speeds via the WebVibration API,\nwhich is the output method that's going to be available to most users.\n\nA quick refresher in the WebVibration API for those not familiar. It's\nquite simple:\n\n```javascript\nnavigator.vibrate([200, 100, 1000, 100]);\n```\n\nVibrate is the only function exposed by the WebVibration API. It takes\neither an int, or an array of ints, representing milliseconds. For the\nabove line, we turn the vibrator on for 200 milliseconds, then off for\n100ms, on for 1 second, off for 100, then just off forever.\n\nThis is great if you want to give someone a quick buzz or two to let\nthem know they got an email/phone call, touched the screen, etc...\nHowever, for other uses of vibrators, it's not going to do you a lot\nof good.\n\nSo how can we set varying speeds with an API that only allows us to\nturn a motor on and off? Answering this requires a bit of background\nin how digitally controlled motors work.\n\nWhat we're going to do is create our own Pulse Width Modulation (PWM).\nPWM is a way of setting the speed of a motor by turning its power\nsource on and off very, very quickly (technically known as \"setting\nand varying the duty cycle\"). If you want a motor to run at 70% duty\ncycle (so 70% of its full capacity for a non-existantly perfect motor\nbut shut up this is an example), you turn the power on for 70% of a\ncertain duration, off for 30%. So let's say our duration is 1\nsecond. We'd have power on for 700ms, off for 300ms. Easy, right?\n\nExcept for the fact that durations on microcontrollers are usually in\nthe milliseconds range if not less. The maximum resolution we can get\nwith WebVibration is _technically_ 1 millisecond, but this is not at\nall a real time guarantee. We also have to factor in the javascript\nscheduler, the communications with the IO thread that is talking to\nthe hardware in the browser core, and so on. So all we're guaranteed\nis that, at some point after 1ms, things will change.\n\nShit.\n\nThis fact doesn't really end our hopes, just lessens them slightly.\nThis is due to the fact that we're running a motor with a load\nattached to it. Since there's a weight attached to the motor (which is\nwhat makes it vibrate since it's spinning and constantly moving the\ncenter of gravity), it takes multiple milliseconds to spin up, and\nmultiple milliseconds to spin down again. That means that we've got\nenough time in javascript to turn off power before the motor gets\ngoing at full speed, then turn it back on before it stops. The\nvibration that happens via these means may not be smooth, but we will\nat least get some approximation of speeds, and possibly some\ninteresting textures.\n\n### Audio Vibrator Control ###\n\nThis is where the discussion of how audio vibration works goes once I\nhave time to write it. For now, just know it's a volume controller and\nthat's it. It really is that simple.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqdot%2Fjiggly.js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqdot%2Fjiggly.js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqdot%2Fjiggly.js/lists"}