# Vibe

> A photocell vibe device: a lamp that pulses on four phase-shift stages, in chorus or vibrato, with its speed, intensity and level, a panel that draws the lamp, a Web Audio engine and tools for agents.

```tsx
"use client";

import { useState } from "react";
import { VibePanel } from "@/components/audio-ui/devices/vibe/panel";
import { useDeviceLoop } from "@/hooks/use-device-loop";
import { useMasterBus } from "@/hooks/use-master-bus";
import {
  type VibeState,
  vibeDevice,
} from "@/components/audio-ui/devices/vibe/device";
import { createVibeEngine } from "@/components/audio-ui/devices/vibe/engine";

const MASTER_VOLUME = 0.7;

/**
 * A photocell vibe you can plug in: its state, a panel that draws the lamp and an engine that plays it, each its own file. Play the loop, switch between chorus and vibrato and turn the speed and the intensity.
 */
export function BlockVibe() {
  const [state, setState] = useState<VibeState>(() => vibeDevice.defaults());
  const master = useMasterBus(MASTER_VOLUME);
  useDeviceLoop({
    create: createVibeEngine,
    destination: master,
    state,
  });
  return (
    <div className="rounded-xl h-full w-full min-w-0">
      <VibePanel onValueChange={setState} value={state} />
    </div>
  );
}
```

A photocell vibe. A lamp pulses inside a box, and four light cells around it set four phase-shift stages: the brighter the lamp, the higher each stage turns the phase around. The stages sit far apart, so the sound sweeps in a lopsided, throbbing way rather than as an even phaser does, and the lamp lights at once and fades slowly, so the sweep rises quickly and falls back slowly. In Chorus mode the shifted sound is mixed with the dry one, for moving notches; in Vibrato mode it plays alone, and its moving phase is heard as pitch. It is a [device](/docs/devices): a state, a panel, an engine and tools, each its own file.

## Installation

**CLI**

```bash
npx shadcn@latest add @audio-ui/vibe
```

It installs the device's state, its engine and its panel to `components/audio-ui/devices/vibe/`. The demo above, which wires them to a loop, is `@audio-ui/block-vibe`.

**Manual**

**1. Install the packages:**

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

**2. Add the pieces you want. All of them, or only the state and the panel if your engine is elsewhere:**

```bash
npx shadcn@latest add @audio-ui/vibe-device @audio-ui/vibe-panel @audio-ui/vibe-engine
```

**3. Copy and paste the demo that wires them, if you want it.**

```tsx title="components/examples/block-vibe.tsx"
"use client";

import { useState } from "react";
import { VibePanel } from "@/components/audio-ui/devices/vibe/panel";
import { useDeviceLoop } from "@/hooks/use-device-loop";
import { useMasterBus } from "@/hooks/use-master-bus";
import {
  type VibeState,
  vibeDevice,
} from "@/components/audio-ui/devices/vibe/device";
import { createVibeEngine } from "@/components/audio-ui/devices/vibe/engine";

const MASTER_VOLUME = 0.7;

/**
 * A photocell vibe you can plug in: its state, a panel that draws the lamp and an engine that plays it, each its own file. Play the loop, switch between chorus and vibrato and turn the speed and the intensity.
 */
export function BlockVibe() {
  const [state, setState] = useState<VibeState>(() => vibeDevice.defaults());
  const master = useMasterBus(MASTER_VOLUME);
  useDeviceLoop({
    create: createVibeEngine,
    destination: master,
    state,
  });
  return (
    <div className="rounded-xl h-full w-full min-w-0">
      <VibePanel onValueChange={setState} value={state} />
    </div>
  );
}
```

**Agent**

Give your agent the skill, and it picks the component, installs it and wires it to your audio:

```bash
npx skills add ouestlabs/audio-ui
```

Then ask it:

```text
Add the vibe from audio/ui to my project and wire it to my audio code.
```

To let the agent read the docs live, connect the [MCP server](/docs/mcp). More in [Agent Skill](/docs/agents).

## Controls

The knobs read 0 to 10, and show the value they set in the unit the sound takes.

| Control | Range | Default | What it does |
| --- | --- | --- | --- |
| On | On or off | On | Turns the device on. Off, the signal passes through unchanged. |
| Mode | Chorus, Vibrato | Chorus | Chorus mixes the shifted sound with the dry one; Vibrato plays it alone, heard as pitch. |
| Speed | 0.6 Hz to 12 Hz | 2 Hz | How fast the lamp pulses, from 0.6 Hz to 12 Hz. |
| Intensity | 0 st to 30 st | 18 st | How far the lamp moves the four stages, up to two octaves and a half. |
| Volume | -∞ dB to 2.9 dB | -3.3 dB | The level of the output, unity a little past the middle. |

## Panel

The panel draws the lamp's light over two seconds, over the mode and the knobs, all drawn off while the device is off. `vibeLight(state)` is what it draws, and `lampCycle()` gives one cycle of the light.

```tsx
import { VibePanel } from "@/components/audio-ui/devices/vibe/panel";
import { vibeDevice } from "@/components/audio-ui/devices/vibe/device";

const [state, setState] = useState(() => vibeDevice.defaults());

<VibePanel onValueChange={setState} value={state} />;
```

## Engine

Create it, connect it and update it as for any device: see [The engine](/docs/devices#the-engine).

The sound goes through a warm preamp, then four all-pass stages spread from 90 Hz to 5.2 kHz, each moved in cents by one oscillator whose wave is the lamp's light. Chorus is half dry and half shifted, Vibrato is shifted alone, and off, the sound passes untouched. Every control moves with a ramp, so a turn makes no click.
