# Core

> @audio-ui/core: the framework-agnostic logic under every audio/ui control and device, in modules you import one at a time, the same in React, plain DOM, Vue, Svelte or a worker.

`@audio-ui/core` holds the logic of every control that is not its view: the controller of each one, its geometry, values and their scales, and the sources a view follows outside its render. No framework, no DOM required for the logic, no Web Audio, and no dependency. The React primitives and the custom elements are each one adapter over it; a page of your own can be another. What makes and times the sound is in [Engine](/docs/engine).

It is one package, `npm install @audio-ui/core`, and each module is its own entry point, so a page pays only for what it imports.

## Controls

The controller of each control: its value, its gesture, its keys and its formatting, whatever draws it. [Controllers](/docs/core/controllers) is the contract they share.

| Module | Controls |
| --- | --- |
| [`knob`](/docs/core/knob), [`fader`](/docs/core/fader), [`xypad`](/docs/core/xypad) | One or two bounded values dragged, stepped and typed. |
| [`meter`](/docs/core/meter) | Levels on a scale, their ballistics, painted every frame. |
| [`envelope`](/docs/core/envelope), [`plot`](/docs/core/plot) | Points on a curve, and a plot's axes, paths, ticks and handles. |
| [`piano`](/docs/core/piano), [`pad`](/docs/core/pad) | Keys and pads struck with a velocity. |
| [`sequencer`](/docs/core/sequencer), [`piano-roll`](/docs/core/piano-roll) | Steps and notes on a grid: selection, editing, scales. |
| [`timeline`](/docs/core/timeline), [`waveform`](/docs/core/waveform) | Clips in time, a zoom and a playhead; a recording's peaks and a seek. |

## The root

`@audio-ui/core` itself holds what every module shares: ranges, scales and stepping (`resolveScale`, `roundToStep`), values that change outside a framework (`createSource`, `createStore`), a frame task that sleeps when nothing moves (`createFrameTask`), and the details a change or a commit reports.

```bash
npm install @audio-ui/core
```

```ts
import { getDataAttributes, createFrameTask, isReleased, observeVisibility, clamp, /* … */ } from "@audio-ui/core";
```

- Adapters: `@audio-ui/react/envelope`, `@audio-ui/react/fader`, `@audio-ui/react/knob`, `@audio-ui/react/meter`, `@audio-ui/react/piano`, `@audio-ui/react/piano-roll`, `@audio-ui/react/plot`, `@audio-ui/react/sequencer`, `@audio-ui/react/timeline`, `@audio-ui/react/waveform`, `@audio-ui/react/xypad`, `@audio-ui/elements/knob`, `@audio-ui/elements/piano`, `@audio-ui/elements/piano-roll`, `@audio-ui/elements/plot`, `@audio-ui/elements/timeline`, `@audio-ui/elements/waveform`

| Export | Kind | What it is |
| --- | --- | --- |
| `getDataAttributes` | function | The data attributes a part renders: `data-<part>` (or `data-<component>`), `data-orientation`, `data-disabled`, and `data-<key>` for every other option given, its value as text. |
| `createFrameTask` | function | Runs `step` on animation frames for as long as it returns true, and sleeps otherwise: a painter with nothing left to animate costs no frames until it is woken. |
| `FrameTask` | interface | What `createFrameTask` returns: wake it when something moves, flush it to step at once, stop it for good. |
| `isReleased` | function | A mouse or pen move with no button down: the press was released where this page could not see it, outside the window or over a menu, so the drag it belongs to is over. |
| `observeVisibility` | function | Calls `onChange` when `element` enters or leaves the viewport, so a painter can skip frames nobody sees. |
| `Point` | type | A point on two axes. |
| `clamp` | const | `value` kept within `min` and `max`. |
| `clampFinite` | const | Clamp into `min…max`; a non-finite value (NaN from a 0/0, ±Infinity) falls back to `min`. |
| `clampUnit` | const | `value` kept within 0 and 1. |
| `degToRad` | const | An angle in degrees, in radians. |
| `PI_HALF` | const | A quarter turn in radians: π/2. |
| `quantizeRound` | const | `value` rounded to the nearest multiple of `interval`. |
| `radToDeg` | const | An angle in radians, in degrees. |
| `roundToStep` | function | Snap to `step` with `min` as the origin, without float noise (0.1 + 0.2). |
| `TAU` | const | A full turn in radians: 2π. |
| `isBlackKey` | function | Whether `pitch` falls on a black key of a piano. |
| `pitchClassName` | function | "C", "C#", "D"... |
| `pitchName` | function | "C4" for middle C (MIDI 60), the naming tuners and score editors agree on. |
| `ChangeEventDetails` | interface | What a change reports: why it happened (`reason`), the event behind it, the element that triggered it, and `cancel()` to refuse the change. |
| `CommitEventDetails` | interface | What a commit reports once a gesture ends: why it happened (`reason`) and the event behind it. |
| `createChangeEventDetails` | function | The details of a change for `reason` and `event`, with `cancel()` to refuse it and `allowPropagation()` to let the event go on. |
| `createPairFormatter` | function | Formats two numbers as one string ("0.3, 0.4"). |
| `moveRange` | function | Moves one edge of `origin` by `delta`, or the whole range, without leaving the timeline. |
| `normalizeRange` | function | Orders a range's edges and keeps them on the timeline. |
| `RangeEdge` | type | What a change moves: one edge, or the whole range with `both`. |
| `RangeLimits` | interface | What a range is kept within: the timeline's length and the shortest it may be. |
| `RangeValue` | type | A stretch of a timeline, `[start, end]` in its units. |
| `LINEAR_SCALE` | const | Even steps: the right feel for levels, times and anything heard in differences. |
| `LOGARITHMIC_SCALE` | const | Even ratios: the right feel for frequency, Q, ratios and times heard in proportions, where a linear sweep hides the useful range in its first few degrees. |
| `ParameterScale` | interface | How a value maps onto a control's travel, and back. |
| `ParameterScaleProp` | type | A scale as an option takes it: `"linear"`, `"log"`, or a scale of your own. |
| `resolveScale` | function | The scale an option names: `"linear"` and `"log"` as `LINEAR_SCALE` and `LOGARITHMIC_SCALE`, a scale of your own as it is. |
| `createSource` | function | Creates a source you push to yourself, from an audio callback, a WebSocket, a worker or a test: call `set` with each new reading, and whatever reads the source follows. |
| `Source` | interface | A value that changes outside React, in the shape `useSyncExternalStore` expects: `subscribe` registers a listener called on each change, and `getSnapshot` returns the current value. |
| `WritableSource` | interface | A source that also takes values: what `createSource` returns. |
| `createStore` | function | A store holding `initial`: `set` tells every listener, unless the value is the same one. |
| `Store` | interface | A value that can be read and observed outside React, in the shape `useSyncExternalStore` expects. |

## Adapters

**In React**

- [React](/docs/react): `@audio-ui/react`, the headless primitives.

**In Vue, Svelte, Web and any framework**

- [Elements](/docs/elements): `@audio-ui/elements`, the primitives as custom elements, for any framework.

- [Engine](/docs/engine): `@audio-ui/engine`, the audio logic: devices, musical time, levels, MIDI input, scales and the clip player.

**In React**

- [Registry](/docs/registry): the styled components, devices, hooks and libraries you install and own.

