{"_id":"@amplib/devices","_rev":"2-61f90ad6d685bdccfd8f41c5b84a41cf","name":"@amplib/devices","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.0":{"name":"@amplib/devices","version":"0.1.0","author":{"name":"Another Machine"},"license":"Apache-2.0","_id":"@amplib/devices@0.1.0","maintainers":[{"name":"jakealbaugh","email":"jake.albaugh@gmail.com"}],"homepage":"https://amplib.app/devices","bugs":{"url":"https://github.com/another-machine/public-library/issues"},"dist":{"shasum":"6e85abab12bbed6f3fc27251684c4e7678c3d5dc","tarball":"https://registry.npmjs.org/@amplib/devices/-/devices-0.1.0.tgz","fileCount":6,"integrity":"sha512-bBdK/oiCPLIfEktAoNMVxwX5NpTERjulES4k+y8glK2f29xa52qKYk53yBDchaHIyeLCduHALl2fWrrovA4eIw==","signatures":[{"sig":"MEYCIQChJHMvc9tjV2z7c9aII8T8BgmnVIjxNCbKDwRuIFZ5mQIhAPwcc4xQp+X+wtKNdiIp/7vo1SS/A+c7HcZV7pneIlYY","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":55175},"main":"dist/index.js","tsup":{"dts":true,"clean":true,"entry":["src/index.ts"],"format":"esm","minify":false,"sourcemap":true,"splitting":false},"type":"module","types":"dist/index.d.ts","gitHead":"12d2a635a582bea9ae238081cadb15924fd5ffac","scripts":{"build":"tsup","watch":"tsup --watch","prepack":"npm run build"},"_npmUser":{"name":"jakealbaugh","email":"jake.albaugh@gmail.com"},"repository":{"url":"git+https://github.com/another-machine/public-library.git","type":"git","directory":"packages/amplib-devices"},"_npmVersion":"10.2.4","description":"A simplified interface for engaging with common MIDI devices and mapping actions to specific messages, user media, and device orientation.","directories":{},"_nodeVersion":"20.11.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/devices_0.1.0_1785526835630_0.6367088973747832","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@amplib/devices","description":"A simplified interface for engaging with common MIDI devices and mapping actions to specific messages, user media, and device orientation.","version":"0.2.0","main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"homepage":"https://amplib.app/devices","repository":{"type":"git","url":"git+https://github.com/another-machine/public-library.git","directory":"packages/amplib-devices"},"tsup":{"entry":["src/index.ts"],"clean":true,"dts":true,"format":"esm","minify":false,"sourcemap":true,"splitting":false},"scripts":{"build":"tsup","watch":"tsup --watch","prepack":"npm run build"},"author":{"name":"Another Machine"},"license":"Apache-2.0","type":"module","_id":"@amplib/devices@0.2.0","gitHead":"6ab555d654557727f58d412d2d3dcc04ea89e6e2","bugs":{"url":"https://github.com/another-machine/public-library/issues"},"_nodeVersion":"20.11.0","_npmVersion":"10.2.4","dist":{"integrity":"sha512-anRz+XCmcwvl97l6ugloRwHN7hwowaEVd2vfvoNnnLDuNJZWPrqyGs8j8buAH61riDPFet9tFQGIXOSPUjSc7g==","shasum":"7e365fe578476a7b258e942d28d0a9063c74cda3","tarball":"https://registry.npmjs.org/@amplib/devices/-/devices-0.2.0.tgz","fileCount":6,"unpackedSize":76350,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQC1CqsQaRsZwNi2mCqIDIuk6yVuBzP2HzXL7rM47OQf1wIhANjDoEBHio8oD1PpS9rsH9nJvx01nxuhnvoLUHXwIe30"}]},"_npmUser":{"name":"jakealbaugh","email":"jake.albaugh@gmail.com"},"directories":{},"maintainers":[{"name":"jakealbaugh","email":"jake.albaugh@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/devices_0.2.0_1785527882477_0.976501577415164"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-31T19:40:35.456Z","modified":"2026-07-31T19:58:02.831Z","0.1.0":"2026-07-31T19:40:35.789Z","0.2.0":"2026-07-31T19:58:02.621Z"},"bugs":{"url":"https://github.com/another-machine/public-library/issues"},"author":{"name":"Another Machine"},"license":"Apache-2.0","homepage":"https://amplib.app/devices","repository":{"type":"git","url":"git+https://github.com/another-machine/public-library.git","directory":"packages/amplib-devices"},"description":"A simplified interface for engaging with common MIDI devices and mapping actions to specific messages, user media, and device orientation.","maintainers":[{"name":"jakealbaugh","email":"jake.albaugh@gmail.com"}],"readme":"# @amplib/devices\n\nThin wrappers over the browser APIs for hardware a machine wants to listen to:\nMIDI controllers, the motion and orientation sensors, the camera and microphone,\nand the GPS.\n\n```ts\nimport { MIDI, type MIDIEvent } from \"@amplib/devices\";\n\nconst midi = new MIDI({\n  onEvent: (event: MIDIEvent) => {\n    if (event.type === \"noteon\") console.log(event.a?.value, event.b?.ratio);\n  },\n});\n\nawait midi.initialize(); // prompts for MIDI access\nmidi.notifyAll(new Uint8Array([0x90, 60, 127])); // to every output\n```\n\n## Modules\n\n| Module              | Description                                                            |\n| ------------------- | ---------------------------------------------------------------------- |\n| `MIDI`              | Connects every input and output, and keeps up as devices come and go    |\n| `MIDIEvent`         | One decoded message — channel, type, and up to two described data bytes |\n| `DeviceMovement`    | `devicemotion`, behind the iOS permission prompt                       |\n| `DeviceOrientation` | `deviceorientation` — `absolute`, `alpha`, `beta`, `gamma`             |\n| `CameraStream`      | A camera you can enumerate and cycle between, stopping the old tracks   |\n| `ScreenStream`      | Screen, window or tab capture, with an `onEnded` for user-side stops    |\n| `MicrophoneStream`  | Microphone input, with voice processing off by default                 |\n| `UserMediaStream`   | `getUserMedia` plus the device list, split into audio and video inputs  |\n| `Geolocation`       | `Geolocation.get()` — the current coordinates, as a promise             |\n\n## Design\n\n**The microphone is unprocessed by default.** Browsers turn on echo\ncancellation, noise suppression and automatic gain control unless told\notherwise, because they assume a voice call. For anything that *measures* the\nsignal — pitch detection, chroma analysis, level metering — those are\ndestructive: noise suppression eats sustained tones it takes for background, and\nAGC rewrites the amplitude you were trying to read. `MicrophoneStream` disables\nall three unless you pass `processing: true`.\n\n**Starting a stream stops the previous one.** `CameraStream.start` and\n`cycle` stop the old tracks first. Calling `getUserMedia` again without doing\nthat leaves the previous camera open — on a phone the indicator light stays lit,\nand the device may refuse the second request outright.\n\n**Devices are enumerated after permission, not before.** Labels come back empty\nand the list can be incomplete until a stream has been granted, so\n`CameraStream` enumerates as part of `start` rather than offering a device list\nthat would be useless when asked for too early.\n\n**A screen capture can end without your UI knowing.** The user can stop sharing\nfrom browser chrome at any time. `ScreenStream.onEnded` is part of the API for\nthat reason — without it an app sits on a dead stream showing a frozen frame.\n\n**Three classes rather than one.** A camera that cycles, a capture that can be\nrevoked, and a microphone that must not be processed have almost nothing in\ncommon beyond calling into `mediaDevices`. `UserMediaStream` remains for the\none-shot case.\n\n**Raw MIDI bytes are described, not just delivered.** `MIDIEvent` decodes a\nstatus byte into a `type` and a channel, and turns each of the two data bytes\ninto an `EventData` carrying `value` (0–127), `ratio` (0–1) and its own `type`.\nReading `event.b?.ratio` to get a fader position is the point — the alternative\nis every consumer rewriting the same mask-and-divide against the spec.\n\n**Connection changes arrive as events too.** `MIDI` subscribes to `statechange`\nand adds or drops ports as they appear, so unplugging a controller mid-set does\nnot leave a dead entry in `inputs`. A connect or disconnect reaches the same\n`onEvent` handler as a note, with a null channel.\n\n**Initialization is always explicit.** `MIDI`, `DeviceMovement` and\n`DeviceOrientation` each have an `initialize()` separate from their constructor,\nbecause each one triggers a permission prompt — MIDI access, and\n`requestPermission()` for the sensors on iOS. Constructing is cheap and silent;\nyou choose when the user gets asked.\n\n## Requirements\n\nBrowser only. Every module reaches for `navigator` and there is no Node build.\n`DeviceMovement`, `DeviceOrientation`, `UserMediaStream` and `Geolocation` all\nrequire a secure context, so they work over `https://` and on `localhost` and\nnowhere else.\n\nWeb MIDI is not universally implemented. Where it is missing,\n`navigator.requestMIDIAccess` is undefined and `MIDI.initialize()` rejects\nrather than degrading — guard the call if a controller is optional to your app.\n\nThe published types reference `MIDIPort` and `MIDIMessageEvent`, which live in\nTypeScript's DOM lib rather than in a separate `@types` package. A consumer\ncompiling without `\"lib\": [\"DOM\"]` will not resolve them.\n","readmeFilename":"README.md"}