Task: Add voice character selection and builder

Add voice character selection and builder

Create game voice characters with different speech rate and pitch settings so children can choose a comfortable option, and add a custom character builder.

Goal

Add a system of voice characters (characters) to the application, through which a child can choose a suitable voiceover style in a playful way.

Main reason: different children may be more comfortable with different speech rates and pitch levels. Instead of technical rate / pitch settings, provide a choice through understandable characters.

Basic Idea

Each character stores a set of settings for SpeechSynthesisUtterance:

type VoiceCharacter = {
  id: string
  name: string
  rate: number
  pitch: number
  volume?: number
  voiceName?: string
  avatar?: string
}

Example:

const characters: VoiceCharacter[] = [
  {
    id: 'calm-bear',
    name: 'Bear Cub',
    rate: 0.75,
    pitch: 0.85,
  },
  {
    id: 'default-friend',
    name: 'Friend',
    rate: 1,
    pitch: 1,
  },
  {
    id: 'fast-bird',
    name: 'Little Bird',
    rate: 1.15,
    pitch: 1.35,
  },
]

Usage:

const utterance = new SpeechSynthesisUtterance(text)

utterance.lang = 'ru-RU'
utterance.rate = character.rate
utterance.pitch = character.pitch
utterance.volume = character.volume ?? 1

Character Selection

A separate character selection UI is needed:

  • a card with the name and visual image;
  • a preview button;
  • active/selected character;
  • saving the selection for future exercises;
  • the ability to quickly switch to another character.

Ideally, the selection should feel like a game setting rather than a system audio config.

Character Builder

Provide a separate builder right away where you can create your own character.

Minimum parameters:

  • name;
  • rate β€” speech rate;
  • pitch β€” voice pitch;
  • volume if necessary;
  • selection of one of the available system voices;
  • visual image/avatar;
  • preview on a test phrase.

Example of builder state:

type VoiceCharacterDraft = {
  name: string
  rate: number
  pitch: number
  volume: number
  voiceName?: string
  avatar?: string
}

Setting Ranges

Do not show technical values to the child as the main interface. Internally, Web Speech API numeric ranges can be used, but the UI is better made intuitive:

Speed:
slow ←─────●─────→ fast

Pitch:
low ←─────●─────→ high

For adults/editors, exact values can be displayed additionally.

Preview

The builder must have a preview button:

const previewCharacter = (
  character: VoiceCharacterDraft,
  text = 'Hello! Let\'s learn together.',
) => {
  window.speechSynthesis.cancel()

  const utterance = new SpeechSynthesisUtterance(text)
  utterance.lang = 'ru-RU'
  utterance.rate = character.rate
  utterance.pitch = character.pitch
  utterance.volume = character.volume

  const voice = window.speechSynthesis
    .getVoices()
    .find(item => item.name === character.voiceName)

  if (voice) {
    utterance.voice = voice
  }

  window.speechSynthesis.speak(utterance)
}

Architecture

It is important to separate the character from the voiceover mechanism itself.

VoiceCharacter
↓
speech settings
↓
SpeechPlayer / Pronouncer
↓
SpeechSynthesisUtterance

That means SpeechPlayer should not know about a specific "Bear Cub" or "Little Bird". It receives ready-made parameters.

Storage

Provide for:

  • built-in application characters;
  • user characters;
  • active selected character;
  • saving user choice between sessions.

Choose specific storage within the project architecture: local state, localStorage, or a server entity if characters need to be synchronized between devices.

Definition of Done

A child can choose one of the ready-made voice characters, hear the difference in speech rate/pitch, use it for further voiceovers, and also create their own character through a simple builder and immediately listen to the result.