Voice Interface Builder Skill
I help you build voice-enabled interfaces using the Web Speech API and modern voice technologies.
What I Do
Speech Recognition:
Voice commands and controls Voice-to-text input Continuous dictation Command detection
Text-to-Speech:
Reading content aloud Voice feedback and notifications Multilingual speech output Voice selection and customization
Voice UI:
Voice-first interfaces Accessibility features Hands-free controls Voice search Web Speech API Basics Speech Recognition // hooks/useSpeechRecognition.ts 'use client' import { useState, useEffect, useRef } from 'react'
interface SpeechRecognitionOptions { continuous?: boolean language?: string onResult?: (transcript: string) => void onError?: (error: string) => void }
export function useSpeechRecognition({
continuous = false,
language = 'en-US',
onResult,
onError
}: SpeechRecognitionOptions = {}) {
const [isListening, setIsListening] = useState(false)
const [transcript, setTranscript] = useState('')
const recognitionRef = useRef
useEffect(() => { if (typeof window === 'undefined') return
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition
if (!SpeechRecognition) {
console.warn('Speech recognition not supported')
return
}
const recognition = new SpeechRecognition()
recognition.continuous = continuous
recognition.lang = language
recognition.interimResults = true
recognition.onresult = event => {
const transcript = Array.from(event.results)
.map(result => result[0].transcript)
.join('')
setTranscript(transcript)
onResult?.(transcript)
}
recognition.onerror = event => {
console.error('Speech recognition error:', event.error)
onError?.(event.error)
setIsListening(false)
}
recognition.onend = () => {
setIsListening(false)
}
recognitionRef.current = recognition
return () => {
recognition.stop()
}
}, [continuous, language, onResult, onError])
const start = () => { if (recognitionRef.current && !isListening) { recognitionRef.current.start() setIsListening(true) } }
const stop = () => { if (recognitionRef.current && isListening) { recognitionRef.current.stop() setIsListening(false) } }
return { isListening, transcript, start, stop } }
Usage:
'use client' import { useSpeechRecognition } from '@/hooks/useSpeechRecognition'
export function VoiceInput() { const { isListening, transcript, start, stop } = useSpeechRecognition({ onResult: (text) => console.log('Recognized:', text) })
return (
{transcript}
Text-to-Speech // hooks/useSpeechSynthesis.ts 'use client' import { useState, useEffect } from 'react'
export function useSpeechSynthesis() {
const [voices, setVoices] = useState
useEffect(() => { if (typeof window === 'undefined') return
const loadVoices = () => {
const availableVoices = window.speechSynthesis.getVoices()
setVoices(availableVoices)
}
loadVoices()
window.speechSynthesis.onvoiceschanged = loadVoices
}, [])
const speak = ( text: string, options?: { voice?: SpeechSynthesisVoice rate?: number pitch?: number volume?: number } ) => { if (typeof window === 'undefined') return
const utterance = new SpeechSynthesisUtterance(text)
if (options?.voice) utterance.voice = options.voice
if (options?.rate) utterance.rate = options.rate // 0.1 - 10
if (options?.pitch) utterance.pitch = options.pitch // 0 - 2
if (options?.volume) utterance.volume = options.volume // 0 - 1
utterance.onstart = () => setSpeaking(true)
utterance.onend = () => setSpeaking(false)
utterance.onerror = () => setSpeaking(false)
window.speechSynthesis.speak(utterance)
}
const cancel = () => { if (typeof window !== 'undefined') { window.speechSynthesis.cancel() setSpeaking(false) } }
return { speak, cancel, speaking, voices } }
Usage:
'use client' import { useSpeechSynthesis } from '@/hooks/useSpeechSynthesis'
export function TextToSpeech() { const { speak, cancel, speaking, voices } = useSpeechSynthesis() const [text, setText] = useState('Hello, how can I help you today?')
return (