组件/VoiceBeam

VoiceBeam

沿元素底边律动的音频响应辉光

已验证自 0.6.2

用法

基础

包裹恰好一个自带圆角的元素;传麦克风的 stream,或用 level 手动驱动。

示例加载中...

麦克风输入

useMicrophone() 关闭回声消除、降噪与自动增益后请求 getUserMedia;start() 必须在点击事件里调用。

<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">想问点什么…</TxCard>
  </TxVoiceBeam>
  <TxButton :aria-pressed="live" @click="live ? mic.stop() : mic.start()">
    {{ live ? '停止' : '说话' }}
  </TxButton>
</template>

宿主预设与配色

type 选择宿主预设,显式传入的几何属性覆盖预设值;colorVariant 选择调色板。

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

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

最佳实践

  • 不要把辉光当作麦克风开着的唯一指示:保留文字状态与按钮的 aria-pressed,并用 role="status" 播报变化。
  • level 传 getter(:level="() => meter.value")而不是响应式数字:getter 每帧采样一次,不触发重渲染。
  • 需保持清晰的文字与控件放到 position: relative; z-index: 5;被包裹元素内的浮层会被裁掉,用 portal 移出。
  • 关闭语音界面时调用 mic.stop(),组合式函数只在卸载时停止音轨。
  • 实例要少:每个实例都有模糊图层与画布,不适合密集列表。

API 参考

属性

属性类型默认值说明
type'default' | 'pill' | 'mobile''default'宿主预设(聊天输入框 / 录音胶囊 / 手机底部),提供几何默认值。
streamMediaStream | nullnull要响应的实时音频;优先于 level。
levelnumber | () => number0无 stream 时的手动电平(0-1)。
sensitivitynumber3.1分析音频的输入增益。
thresholdnumber0.015噪声门(0-1),低于它的电平视为静音。
attack / releasenumber0.325 / 0.86辉光上升与回落的秒数。
idle / breatheDurationnumber0.23 / 5.2静音时的存在感与呼吸周期(秒)。
reach / spreadnumber1.2 / 1.05满电平时的升高与横向扩张倍数。
bandsbooleantrue低 / 中 / 高频段独立驱动各色瓣。
flownumber48满电平下频谱的横向流速(px/s)。
processingbooleanfalse收拢为一束往返行进的光束并保持点亮。
processingDuration / processingLevel / processingEase / processingTravel / processingCurvenumber1.1 / 0.55 / 0.6 / 1.55 / 2.1处理阶段的往返周期、保持亮度、形变时长、行程与缓动。
cornerFollownumber0.45处理阶段辉光沿圆角抬起的程度。
colorVariant'colorful' | 'mono' | 'ocean' | 'sunset' | …'colorful'色瓣调色板。
colorsstring[]无最多七个色瓣颜色,中心优先。
bandColors{ core?, above?, mid?, below? }主题默认光带脊线与色边的颜色。
theme'dark' | 'light' | 'auto''dark'背景适配;auto 跟随系统偏好。
staticColorsbooleanfalse关闭缓慢的色相漂移。
hueRange / hueDurationnumber24 / 40、12 / 8.5色相漂移范围(度)与周期(秒);默认值分暗色 / 亮色。
activebooleantrue关闭时辉光淡出并停止音频分析。
pausedbooleanfalse把辉光、光带与分析冻结在最后一帧。
borderRadiusnumber自动探测圆角半径(px)。
brightness / saturationnumber主题默认辉光亮度与饱和度倍数。
glowSizenumber1辉光模糊半径倍数。
strokeOpacity / innerOpacity / bloomOpacitynumber1描边、内光与光晕层的不透明度倍数。
scalenumber1一次缩放全部像素尺寸。
bend、bandStrength、bandWidth、bandPosition、bandCurve、bandSpread、bandSkew、bandOffset、bandTail、bandTailPosition、bandTailCurve、bandTailOverflow、bandAberrationnumber已调校辉光轮廓与光带的形状。
distortion / distortionDetailnumber0.62 / 2.3光带下方光的横向扭曲强度与噪声粒度。
glowWidth、glowHeight、lobeSpacing、rangeWidth、rangeHeight、softness、coreSize、coreLight、coreLightWidth、coreLightHeight、strokeScale、innerScale、innerHeight、bloomScale、bloomHeightnumber已调校色瓣、可见范围、核心与光晕的几何。
strengthnumber1整体效果不透明度(0-1),不影响子元素。
cssstring无追加在生成样式表之后的 CSS;{id} 按实例替换。

插槽

插槽参数说明
default-被包裹的元素;光束图层渲染在它背后与上方。

事件

事件载荷说明
level(level: number)每帧触发,携带当前展示的平滑电平。
activate-淡入完成时触发。
deactivate-淡出完成时触发。

CSS 变量

变量来源说明
--voice-strengthstrength光束图层不透明度(0-1)。
--voice-stroke-opacity / --voice-inner-opacity / --voice-bloom-opacity宿主样式各层不透明度倍数,与 strokeOpacity / innerOpacity / bloomOpacity 相乘;组件不写入。

概述

  • 按子元素的 border-top-left-radius(取不到时为 16 px)裁剪,光束贴合元素边缘。
  • 全页共用一个约 60 fps 封顶的 requestAnimationFrame 循环;实例滚出视口(256 px 边距)后注销并释放分析器。
  • 每页共用一个 AudioContext,每个 stream 一个 source 节点(引用计数),每个实例一个分析器;音频只分析,不播放。
  • 使用 stream 时读取 RMS 电平与三个频段(80-300、300-2000、2000-6000 Hz)。
  • 减少动态效果时停止待机呼吸、色彩流动、色相漂移、扭曲与处理扫描;对声音的反应保留,因为它本质是电平表。

技术实现

  • styles.ts、presets.ts、voice-driver.ts、audio.ts、color.ts 逐字移植自 Jakubantalik/Libraries · voice-glow(MIT © Jakub Antalik);useMicrophone 是上游 React hook 的 Vue 移植。
  • 源码:packages/tuffex/packages/components/src/voice-beam/。
查看源码
packages/tuffex/packages/components/src/voice-beam/index.ts