Components/VoiceBeam

VoiceBeam

An audio-reactive glow along the bottom edge of the element it wraps.

VerifiedSince 0.6.2

Usage

Basic

Wrap exactly one element that carries its own radius; feed it a microphone stream, or drive it with level.

Loading demo...

Microphone Input

useMicrophone() requests getUserMedia with echo cancellation, noise suppression, and auto gain off; call start() from a click.

<script setup lang="ts">
import { useMicrophone } from '@talex-touch/tuffex/pro'

const mic = useMicrophone()
const live = computed(() => mic.state.value === 'live')
</script>

<template>
  <TxVoiceBeam :stream="mic.stream.value" :processing="transcribing">
    <TxCard :radius="16" :padding="24" shadow="none">Ask anything…</TxCard>
  </TxVoiceBeam>
  <TxButton :aria-pressed="live" @click="live ? mic.stop() : mic.start()">
    {{ live ? 'Stop' : 'Listen' }}
  </TxButton>
</template>

Host Presets and Palettes

type picks the host preset, and any geometry prop you pass wins over it; colorVariant picks the palette.

<template>
  <TxVoiceBeam type="pill" color-variant="ocean" :scale="0.9">
    <div class="pill">Recording…</div>
  </TxVoiceBeam>

  <TxVoiceBeam type="mobile" color-variant="candy" :level="() => 0.8">
    <div class="screen">Listening</div>
  </TxVoiceBeam>
</template>

Best Practices

  • Never let the glow be the only sign the mic is live: keep a text status and the button's aria-pressed, and announce changes with role="status".
  • Pass level a getter (:level="() => meter.value"), not a reactive number; the getter is sampled once per frame with no re-render.
  • Put content that must stay crisp at position: relative; z-index: 5; overlays inside the wrapped element get clipped, so portal them out.
  • Call mic.stop() when the voice UI closes; the composable stops tracks only on unmount.
  • Keep instances few: each runs blurred layers and a canvas, so it doesn't suit dense lists.

API Reference

Props

PropTypeDefaultDescription
type'default' | 'pill' | 'mobile''default'Host preset (chat input, recording pill, phone bottom) that seeds the geometry props.
streamMediaStream | nullnullLive audio to react to; wins over level.
levelnumber | () => number0Manual level (0-1) used when there is no stream.
sensitivitynumber3.1Input gain on the analysed audio.
thresholdnumber0.015Noise gate (0-1); levels below it read as silence.
attacknumber0.325Seconds the glow takes to rise.
releasenumber0.86Seconds the glow takes to settle.
idlenumber0.23Resting presence (0-1), so the beam never looks dead.
breatheDurationnumber5.2Idle breathing period in seconds.
reachnumber1.2How tall the glow grows at full level.
spreadnumber1.05How far the glow widens at full level.
bandsbooleantrueLets low, mid, and high bands move the lobes independently.
flownumber48Sideways travel of the spectrum in px/s at full level.
processingbooleanfalseGathers the glow into a travelling beam and holds it lit.
processingDurationnumber1.1Seconds for one pass of the processing beam.
processingLevelnumber0.55How lit the glow stays while processing.
processingEasenumber0.6Seconds of the morph in either direction.
processingTravelnumber1.55How far the processing beam travels to each side.
processingCurvenumber2.1How the sweep eases into each turn.
cornerFollownumber0.45How much the glow rides the corner arcs while processing.
colorVariant'colorful' | 'mono' | 'ocean' | 'sunset' | …'colorful'Palette for the lobes.
colorsstring[]noneUp to seven lobe colours, centre first.
bandColors{ core?, above?, mid?, below? }theme defaultsColours of the band's ridge and fringes.
theme'dark' | 'light' | 'auto''dark'Background adaptation; auto follows the system.
staticColorsbooleanfalseTurns off the slow hue drift.
hueRangenumber24 / 40Hue drift range in degrees (dark / light default).
hueDurationnumber12 / 8.5Hue drift period in seconds (dark / light default).
activebooleantrueOff fades the beam out and stops the audio analysis.
pausedbooleanfalseFreezes glow, band, and analysis on their last frame.
borderRadiusnumberauto-detectedCorner radius in px.
brightness / saturationnumbertheme defaultsGlow multipliers.
glowSizenumber1Bloom blur radius multiplier.
strokeOpacity / innerOpacity / bloomOpacitynumber1Opacity multipliers of the stroke, inner light, and bloom layers.
scalenumber1Multiplies every pixel dimension at once.
bend, bandStrength, bandWidth, bandPosition, bandCurve, bandSpread, bandSkew, bandOffset, bandTail, bandTailPosition, bandTailCurve, bandTailOverflow, bandAberrationnumbertunedShape of the glow's contour and the band along it.
distortion, distortionDetailnumber0.62, 2.3Strength and noise grain of the warp under the band line.
glowWidth, glowHeight, lobeSpacing, rangeWidth, rangeHeight, softness, coreSize, coreLight, coreLightWidth, coreLightHeight, strokeScale, innerScale, innerHeight, bloomScale, bloomHeightnumbertunedLobe, visible-range, core, and halo geometry.
strengthnumber1Overall effect opacity (0-1); the children are untouched.
cssstringnoneCSS appended after the generated stylesheet; {id} is replaced per instance.

Slots

SlotPropsDescription
default-The wrapped element; the beam layers render behind and above it.

Events

EventPayloadDescription
level(level: number)Fires every frame with the smoothed level the beam shows.
activate-Fires when the fade-in completes.
deactivate-Fires when the fade-out completes.

CSS Variables

VariableSourceDescription
--voice-strengthstrengthBeam-layer opacity (0-1).
--voice-stroke-opacity / --voice-inner-opacity / --voice-bloom-opacityhost CSSPer-layer opacity multipliers, multiplied with strokeOpacity / innerOpacity / bloomOpacity; the component never sets them.

Overview

  • It clips to the child's border-top-left-radius (16 px when none is found), so the beam hugs the element edge.
  • One shared requestAnimationFrame loop, capped at about 60 fps, drives every instance; an instance scrolled offscreen (256 px margin) unregisters and releases its analyser.
  • One AudioContext is shared per page, with one source node per stream (reference-counted) and one analyser per instance. Audio is analysed, never played.
  • With a stream, the analyser reads the RMS level plus three voice bands (80-300, 300-2000, 2000-6000 Hz).
  • Under reduced motion, the idle breathing, colour flow, hue drift, distortion, and processing sweep stop; the reaction to sound stays, since it is a meter.

Technologies

  • styles.ts, presets.ts, voice-driver.ts, audio.ts, and color.ts are verbatim ports of Jakubantalik/Libraries · voice-glow (MIT © Jakub Antalik); useMicrophone is the Vue port of its React hook.
  • Source: packages/tuffex/packages/components/src/voice-beam/.
查看源码
packages/tuffex/packages/components/src/voice-beam/index.ts