# Device

> Haptics, the QR scanner, the clipboard, links, Lia's own screens, Face ID and Touch ID, and the motion sensors. From the Lia developer docs: https://docs.lialabs.org/reference/sdk-device

## Haptics

### Lia.haptic(kind)

A tap the person feels. Resolves with `null`.

```js
Lia.haptic("success");
```

| `kind` | Feels like |
| --- | --- |
| `"light"` (the default), `"medium"`, `"heavy"`, `"rigid"`, `"soft"` | A tap, from light to heavy |
| `"success"`, `"warning"`, `"error"` | A result |
| `"selection"` | A tick, for a choice changing |

An unknown kind plays `"light"`. Each haptic is a round trip to Lia, so don't play one every frame of a game.

## Scanning and the clipboard

### Lia.scanQr(options)

Opens Lia's QR scanner over your app. Resolves with the code's text, or `null` if the person closed it.

```js
const text = await Lia.scanQr({ text: "Scan the code on the table" });
```

| Option | Type | |
| --- | --- | --- |
| `text` | string | Optional, under the scanner's window, up to 64 characters. |

Errors: `bad_text`, `busy`.

### Lia.copyText(text)

Copies text to the clipboard, and Lia says it's copied. Resolves with `null`.

| Parameter | Type | |
| --- | --- | --- |
| `text` | string | Up to 4096 characters. |

Errors: `bad_text`, `unsupported`.

### Lia.readClipboard()

The text on the clipboard, or `null`. On iPhone, the phone asks the person first.

```js
const pasted = await Lia.readClipboard();
```

## Links

### Lia.openLink(url, options)

Opens a web page. Your frame only shows your own pages, so use this for any other site.

```js
Lia.openLink("https://example.com/terms");               // in Lia's in-app browser, over your app
Lia.openLink("https://example.com", { external: true }); // outside Lia, in the phone's browser
```

| Parameter | Type | |
| --- | --- | --- |
| `url` | string | An https address, up to 2048 characters. |
| `options.external` | boolean | Open it outside Lia. |

Resolves with `null` once the in-app browser is closed (or straight away for `external`). Errors: `bad_url`.

### Lia.openLiaLink(screen)

Opens one of Lia's own screens. Pages close your app first (asking, if you turned [closing confirmation](/reference/sdk-layout#lia-enableclosingconfirmation) on) and open as themselves; sheets open over your app, which stays.

```js
Lia.openLiaLink("mine"); // Lia's mining sheet, over your app
```

| `screen` | Opens | Your app |
| --- | --- | --- |
| `"invite"` | Invite friends to Lia | Closes |
| `"strides"` | Strides | Closes |
| `"activity"` | The person's activity | Closes |
| `"send"` | Send $LIA | Closes |
| `"apps"` | The Apps Center | Closes |
| `"streak"` | The check-in streak | Stays |
| `"mine"` | Mining | Stays |
| `"receive"` | Receive $LIA | Stays |

Resolves with `{ closed }`: `true` if your app closed, `false` if it stayed (or the person chose to stay). Errors: `unknown_screen`, `bad_screen`.

## Face ID and Touch ID

### Lia.biometric

Ask the person to confirm it's them, with the phone's Face ID, Touch ID or fingerprint, before something sensitive in your app. Your app only learns whether they passed.

#### Lia.biometric.init()

Whether the phone can do it. Resolves with `{ available, type }`: `available` is true when the phone has it and it's set up; `type` is `"face"`, `"finger"` or `"unknown"`.

#### Lia.biometric.authenticate(options)

Asks the person to confirm. Resolves with `{ authenticated }`. If they can't use biometrics, the phone may offer its passcode instead.

```js
const { available } = await Lia.biometric.init();
if (available) {
  const { authenticated } = await Lia.biometric.authenticate({ reason: "Confirm it's you to open your vault" });
}
```

| Option | Type | |
| --- | --- | --- |
| `reason` | string | Optional, shown by the phone, up to 128 characters. Lia's own words when left out. |

Errors: `unsupported`, `busy`, `bad_reason`.

## Motion

Three sensors, each with `start`, `stop`, `isStarted` and its latest reading. Readings arrive as events while a sensor runs; it stops when your app closes. All three are optional on phones: `start()` fails with `unsupported` where there's none.

| Sensor | Reading | Units | Event |
| --- | --- | --- | --- |
| `Lia.accelerometer` | `x`, `y`, `z` | m/s², gravity included | `"accelerometerChanged"` |
| `Lia.gyroscope` | `x`, `y`, `z` | Rotation rate, radians a second | `"gyroscopeChanged"` |
| `Lia.deviceOrientation` | `alpha`, `beta`, `gamma` | Angles in radians | `"deviceOrientationChanged"` |

```js
await Lia.deviceOrientation.start({ refreshRate: 50 });
Lia.on("deviceOrientationChanged", function (r) {
  steer(r.gamma); // tilting left and right
});
// later
Lia.deviceOrientation.stop();
```

### Lia.accelerometer

| Member | |
| --- | --- |
| `start(options)` | Starts readings. `options.refreshRate`: 20 to 1000 ms between readings, 1000 by default. Resolves with `true`; also fires `"accelerometerStarted"`. Errors: `bad_refresh_rate`, `unsupported`. |
| `stop()` | Stops them. Resolves with `true`; also fires `"accelerometerStopped"`. |
| `isStarted` | Whether it's running. |
| `x`, `y`, `z` | The latest reading, `null` before the first. |

### Lia.gyroscope

The same as `Lia.accelerometer`, with `x`, `y` and `z` rotation rates.

### Lia.deviceOrientation

The same, with `alpha`, `beta` and `gamma`.
