@molecule/app-motion
v1.0.1
Published
Accelerometer and gyroscope interface for molecule.dev
Maintainers
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.tsJSDoc, 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-i18nAPI
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): Vector3Da— 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): numbera— 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(): MotionProviderReturns: The active MotionProvider instance.
hasProvider()
Check if a motion provider has been registered.
function hasProvider(): booleanReturns: Whether a MotionProvider has been bonded.
magnitude(v)
Calculate the magnitude (length) of a 3D vector.
function magnitude(v: Vector3D): numberv— 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): Vector3Dv— 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): voidprovider— MotionProvider implementation to register.
startAccelerometer(callback, options)
Start receiving accelerometer data updates.
function startAccelerometer(
callback: (data: AccelerometerData) => void,
options?: SensorOptions,
): () => voidcallback— 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,
): () => voidcallback— 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,
): () => voidcallback— 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): () => voidcallback— 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,
): () => voidcallback— 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-i18nEvery accessor THROWS until
setProvider()is called — there is no web fallback and no prebuilt provider package ships with molecule; supply aMotionProvider(native runtime, or a thin web one overdevicemotion/deviceorientationevents).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
includesGravitydiffers per source — check the flag onAccelerometerDatabefore applying filters.
Translations
Translation strings are provided by @molecule/app-locales-motion.
