npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@molecule/app-motion

v1.0.1

Published

Accelerometer and gyroscope interface for molecule.dev

Readme

@molecule/app-motion

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Accelerometer and gyroscope interface for molecule.dev.

Framework-agnostic core for motion sensors through a swappable MotionProvider: continuous streams (startAccelerometer, startGyroscope, startMagnetometer, startOrientation, startMotion), one-off reads (getAccelerometer, getGyroscope, getOrientation), a permission flow, and pure gesture helpers (createShakeDetector, createTiltDetector, createStepCounter, vector math).

Quick Start

import {
  createShakeDetector,
  getAccelerometer,
  hasProvider,
  requestPermission,
} from '@molecule/app-motion'

async function undoOnShake(undo: () => void): Promise<() => void> {
  if (!hasProvider()) return () => {} // no provider wired — skip
  if ((await requestPermission()) !== 'granted') return () => {}
  const shake = createShakeDetector(undo) // self-wires the accelerometer
  shake.start()
  return () => shake.stop() // ALWAYS stop on unmount — sensors drain battery
}

async function logTilt(): Promise<void> {
  const { x, y, z } = await getAccelerometer() // one-off read
  console.log(x, y, z)
}

Type

native

Installation

npm install @molecule/app-motion @molecule/app-bond @molecule/app-i18n

API

Interfaces

AccelerometerData

Accelerometer data

interface AccelerometerData extends Vector3D {
  /** Timestamp */
  timestamp: number
  /** Whether gravity is included */
  includesGravity: boolean
}

GyroscopeData

Gyroscope rotation rate reading (x/y/z radians per second with timestamp).

interface GyroscopeData extends Vector3D {
  /** Timestamp */
  timestamp: number
}

MagnetometerData

Magnetometer data

interface MagnetometerData extends Vector3D {
  /** Timestamp */
  timestamp: number
}

MotionCapabilities

Motion capabilities

interface MotionCapabilities {
  /** Whether motion sensors are supported */
  supported: boolean
  /** Whether accelerometer is available */
  hasAccelerometer: boolean
  /** Whether gyroscope is available */
  hasGyroscope: boolean
  /** Whether magnetometer is available */
  hasMagnetometer: boolean
  /** Whether device orientation is available */
  hasOrientation: boolean
  /** Whether permission is required */
  requiresPermission: boolean
}

MotionData

Combined motion data

interface MotionData {
  /** Accelerometer with gravity */
  accelerationIncludingGravity?: AccelerometerData
  /** Accelerometer without gravity (linear) */
  acceleration?: AccelerometerData
  /** Gyroscope rotation rate */
  rotationRate?: GyroscopeData
  /** Device orientation */
  orientation?: OrientationData
  /** Interval in milliseconds */
  interval: number
  /** Timestamp */
  timestamp: number
}

MotionProvider

Motion provider interface

interface MotionProvider {
  /**
   * Start accelerometer updates
   * @param callback - Called with accelerometer data
   * @param options - Sensor options
   * @returns Stop function
   */
  startAccelerometer(
    callback: (data: AccelerometerData) => void,
    options?: SensorOptions,
  ): () => void

  /**
   * Start gyroscope updates
   * @param callback - Called with gyroscope data
   * @param options - Sensor options
   * @returns Stop function
   */
  startGyroscope(callback: (data: GyroscopeData) => void, options?: SensorOptions): () => void

  /**
   * Start magnetometer updates
   * @param callback - Called with magnetometer data
   * @param options - Sensor options
   * @returns Stop function
   */
  startMagnetometer(callback: (data: MagnetometerData) => void, options?: SensorOptions): () => void

  /**
   * Start device orientation updates
   * @param callback - Called with orientation data
   * @param options - Sensor options
   * @returns Stop function
   */
  startOrientation(callback: (data: OrientationData) => void, options?: SensorOptions): () => void

  /**
   * Start combined motion updates
   * @param callback - Called with motion data
   * @param options - Sensor options
   * @returns Stop function
   */
  startMotion(callback: (data: MotionData) => void, options?: SensorOptions): () => void

  /**
   * Get the current accelerometer reading.
   * @returns The current accelerometer data with x, y, z values and timestamp.
   */
  getAccelerometer(): Promise<AccelerometerData>

  /**
   * Get the current gyroscope reading.
   * @returns The current gyroscope data with x, y, z rotation rates and timestamp.
   */
  getGyroscope(): Promise<GyroscopeData>

  /**
   * Get the current device orientation reading.
   * @returns The current orientation data with alpha, beta, gamma angles and timestamp.
   */
  getOrientation(): Promise<OrientationData>

  /**
   * Get the motion sensor permission status.
   * @returns The permission status: 'granted', 'denied', 'prompt', or 'unsupported'.
   */
  getPermissionStatus(): Promise<MotionPermissionStatus>

  /**
   * Request motion sensor permission (required on iOS 13+).
   * @returns The resulting permission status after the request.
   */
  requestPermission(): Promise<MotionPermissionStatus>

  /**
   * Get the platform's motion sensor capabilities.
   * @returns The capabilities indicating which sensors are available.
   */
  getCapabilities(): Promise<MotionCapabilities>
}

OrientationData

Device orientation data

interface OrientationData {
  /** Alpha (rotation around Z-axis, 0-360) */
  alpha: number
  /** Beta (rotation around X-axis, -180 to 180) */
  beta: number
  /** Gamma (rotation around Y-axis, -90 to 90) */
  gamma: number
  /** Timestamp */
  timestamp: number
  /** Whether orientation is absolute */
  absolute: boolean
}

SensorOptions

Configuration for motion sensor listening (sampling frequency in Hz).

interface SensorOptions {
  /** Sampling frequency in Hz (default: 60) */
  frequency?: number
}

ShakeOptions

Shake detection options

interface ShakeOptions {
  /** Shake threshold acceleration (default: 15) */
  threshold?: number
  /** Minimum shakes to trigger (default: 3) */
  minShakes?: number
  /** Time window in ms (default: 1000) */
  timeWindow?: number
}

Vector3D

3D vector for sensor data

interface Vector3D {
  /** X-axis value */
  x: number
  /** Y-axis value */
  y: number
  /** Z-axis value */
  z: number
}

Types

MotionPermissionStatus

Motion permission status

type MotionPermissionStatus = 'granted' | 'denied' | 'prompt' | 'unsupported'

Functions

createShakeDetector(onShake, options)

Create a shake gesture detector that uses accelerometer data to detect device shaking.

function createShakeDetector(
  onShake: () => void,
  options?: ShakeOptions,
): { start: () => void; stop: () => void }
  • onShake — Called when a shake gesture is detected.
  • options — Shake detection options (threshold, minimum shakes, time window).

Returns: A controller with start and stop methods for the shake detector.

createStepCounter(onStep)

Create a basic step counter using accelerometer peak detection.

function createStepCounter(onStep: (count: number) => void): {
  start: () => void
  stop: () => void
  getCount: () => number
  reset: () => void
}
  • onStep — Called with the cumulative step count each time a step is detected.

Returns: A controller with start, stop, getCount, and reset methods.

createTiltDetector(onChange, options)

Create a tilt detector that calculates pitch and roll angles from accelerometer data.

function createTiltDetector(
  onChange: (tilt: { pitch: number; roll: number }) => void,
  options?: SensorOptions,
): { start: () => void; stop: () => void }
  • onChange — Called with pitch (front-back tilt) and roll (left-right tilt) angles in degrees.
  • options — Sensor options (sampling frequency).

Returns: A controller with start and stop methods for the tilt detector.

cross(a, b)

Calculate the cross product of two 3D vectors.

function cross(a: Vector3D, b: Vector3D): Vector3D
  • a — The first vector.
  • b — The second vector.

Returns: A new Vector3D perpendicular to both input vectors.

dot(a, b)

Calculate the dot product of two 3D vectors.

function dot(a: Vector3D, b: Vector3D): number
  • a — The first vector.
  • b — The second vector.

Returns: The scalar dot product (a.xb.x + a.yb.y + a.z*b.z).

getAccelerometer()

Get the current accelerometer reading.

function getAccelerometer(): Promise<AccelerometerData>

Returns: The current accelerometer data with x, y, z values and timestamp.

getCapabilities()

Get the platform's motion sensor capabilities.

function getCapabilities(): Promise<MotionCapabilities>

Returns: The capabilities indicating which sensors are available.

getGyroscope()

Get the current gyroscope reading.

function getGyroscope(): Promise<GyroscopeData>

Returns: The current gyroscope data with x, y, z rotation rates and timestamp.

getOrientation()

Get the current device orientation reading.

function getOrientation(): Promise<OrientationData>

Returns: The current orientation data with alpha, beta, gamma angles and timestamp.

getPermissionStatus()

Get the motion sensor permission status.

function getPermissionStatus(): Promise<MotionPermissionStatus>

Returns: The permission status: 'granted', 'denied', 'prompt', or 'unsupported'.

getProvider()

Get the current motion provider.

function getProvider(): MotionProvider

Returns: The active MotionProvider instance.

hasProvider()

Check if a motion provider has been registered.

function hasProvider(): boolean

Returns: Whether a MotionProvider has been bonded.

magnitude(v)

Calculate the magnitude (length) of a 3D vector.

function magnitude(v: Vector3D): number
  • v — The 3D vector with x, y, z components.

Returns: The Euclidean magnitude of the vector.

normalize(v)

Normalize a 3D vector to unit length. Returns a zero vector if the input has zero magnitude.

function normalize(v: Vector3D): Vector3D
  • v — The 3D vector to normalize.

Returns: A new Vector3D with unit length pointing in the same direction.

requestPermission()

Request motion sensor permission (required on iOS 13+).

function requestPermission(): Promise<MotionPermissionStatus>

Returns: The resulting permission status after the request.

setProvider(provider)

Set the motion provider.

function setProvider(provider: MotionProvider): void
  • provider — MotionProvider implementation to register.

startAccelerometer(callback, options)

Start receiving accelerometer data updates.

function startAccelerometer(
  callback: (data: AccelerometerData) => void,
  options?: SensorOptions,
): () => void
  • callback — Called with AccelerometerData on each sensor reading.
  • options — Sensor options (sampling frequency).

Returns: A function that stops the accelerometer updates when called.

startGyroscope(callback, options)

Start receiving gyroscope data updates.

function startGyroscope(
  callback: (data: GyroscopeData) => void,
  options?: SensorOptions,
): () => void
  • callback — Called with GyroscopeData on each sensor reading.
  • options — Sensor options (sampling frequency).

Returns: A function that stops the gyroscope updates when called.

startMagnetometer(callback, options)

Start receiving magnetometer data updates.

function startMagnetometer(
  callback: (data: MagnetometerData) => void,
  options?: SensorOptions,
): () => void
  • callback — Called with MagnetometerData on each sensor reading.
  • options — Sensor options (sampling frequency).

Returns: A function that stops the magnetometer updates when called.

startMotion(callback, options)

Start receiving combined motion data (accelerometer, gyroscope, orientation).

function startMotion(callback: (data: MotionData) => void, options?: SensorOptions): () => void
  • callback — Called with combined MotionData on each reading.
  • options — Sensor options (sampling frequency).

Returns: A function that stops the motion updates when called.

startOrientation(callback, options)

Start receiving device orientation updates.

function startOrientation(
  callback: (data: OrientationData) => void,
  options?: SensorOptions,
): () => void
  • callback — Called with OrientationData (alpha, beta, gamma angles) on each reading.
  • options — Sensor options (sampling frequency).

Returns: A function that stops the orientation updates when called.

Injection Notes

Requirements

Peer dependencies:

  • @molecule/app-bond ^1.0.1
  • @molecule/app-i18n ^1.0.1

Runtime Dependencies

  • @molecule/app-bond

  • @molecule/app-i18n

  • Every accessor THROWS until setProvider() is called — there is no web fallback and no prebuilt provider package ships with molecule; supply a MotionProvider (native runtime, or a thin web one over devicemotion/deviceorientation events).

  • iOS WebKit requires requestPermission() from a USER GESTURE (DeviceMotionEvent.requestPermission) on HTTPS — calling it on page load, or on http, rejects without a prompt. Desktop browsers simply have no sensors: treat 'unsupported' as a normal outcome, not an error.

  • Every start* returns a stop function — call it on unmount; a leaked 60 Hz sensor stream is a battery drain and keeps the page from sleeping.

  • Axes/units are normalized by the provider contract (m/s², rad/s), but includesGravity differs per source — check the flag on AccelerometerData before applying filters.

Translations

Translation strings are provided by @molecule/app-locales-motion.