43 KiB
Дизайн Анимированного Персонажа для AI-Компаньона (Психологическое Приложение)
Исследование выполнено: май 2026
Контекст: персонаж — визуальное лицо AI-компаньона в приложении психологической рефлексии. Абстрактный (не человек, не робот). Реагирует на эмоции и голос пользователя.
1. Существующие Примеры Абстрактных AI Персонажей
1.1 Большие платформы
🔵 Siri (Apple) — Waveform / Орб
- Эволюция: Siri прошёл путь от простых волн (iOS 7–12) до живого светящегося шара (iOS 14+) и «гало» вокруг экрана (iOS 18/26)
- Что работает: плавные цветовые переходы синий→фиолетовый→розовый ассоциируются с «думающим» AI без антропоморфизации
- Реализация: Core Animation + Metal шейдеры; собственный рендер Apple
- Эмоциональный эффект: пользователи воспринимают его как «живой», но не угрожающий (Reddit: r/ios26, обсуждение «Type to Siri Wavy Effect»)
- Референс: Apple Human Interface Guidelines — Siri
🟡 Alexa (Amazon) — Кольцо/Ring
- Визуал: круговое световое кольцо: синий = слушает, оранжевый = нет сети, фиолетовый = не беспокоить, белый = регулировка громкости
- Что работает: семиотика цвета как язык состояний — пользователи быстро запоминают коды без слов
- Ограничение для нашего case: слишком «железный», не подходит для эмпатийного контекста
🔮 Google Assistant — Точки / G-шар
- Визуал: 4 цветные точки (синяя, красная, жёлтая, зелёная), анимирующиеся в вол-ну при активации; позже — 3D светящийся «G»
- Что работает: цветовая идентичность бренда, минимализм
- Ограничение: слишком корпоративный, не тёплый
🟢 ChatGPT (OpenAI) — Пульсирующий Шар
- Визуал: анимированный чёрно-белый шар в голосовом режиме Canvas/voice mode; в web — простая анимация печатающегося текста
- Решение: нейтральный ч/б орб не навязывает эмоцию — пользователь сам проецирует
- Реакция пользователей: в Reddit threads (r/ChatGPT) отмечают, что голосовой орб ощущается «медитативно», снижает тревогу перед диалогом
🔵 Microsoft Copilot — Градиентная Орбита
- Визуал: анимированная орбита из синих и фиолетовых полос, морфирующая при ответе
- Что работает: ощущение «умного движения», не угрожающего; подходит для рабочей среды
1.2 Mental Health / Медитация
🧘 Headspace — «Andy» (апельсиновый шар)
- Визуал: простой оранжевый круг с минимальными чертами лица (точки-глаза, дуга-рот)
- Степень абстракции: умеренная — есть лицо, но без носа/ушей
- Что работает: тёплый цвет = дружелюбие, округлость = безопасность
- Референс: Headspace Design System
- Ограничение: лицо делает его «детским» — не подходит для взрослой аудитории
🌊 Calm — Анимированные Фоны
- Подход: Calm отказался от персонажа-компаньона в пользу окружающей среды (вода, листья, луна)
- Вывод для нас: персонаж должен быть частью «среды», а не отдельным элементом
💜 Replika (AI Companion) — 3D Аватар
- Подход: антропоморфный 3D аватар, настраиваемый пользователем
- Минус: тревожная долина (Uncanny Valley), юридические и этические вопросы привязанности
- Вывод: НЕ делать антропоморфный. Наш выбор абстракции — правильный
🌿 Woebot — Минималистичный Робот
- Визуал: простой квадратный «робот» с экраном-лицом
- Что работает: простота снижает тревогу, неантропоморфность делает его «инструментом», а не «существом»
- Ограничение: слишком «роботизированный» для эмпатийного контекста
1.3 Прочие Примеры
🦜 Duolingo — Duo (сова) + Lily
- Duo: антропоморфная сова — зелёная, с глазами; огромный успех с точки зрения вовлечённости
- Lily (AI Video Call, 2025): реализован в Rive — анимированный персонаж с state machine, живущий в видеозвонке
- Кейс-стади Rive: Duolingo использует Rive для интерактивных персонажей, потому что state machine позволяет плавно переходить между сотнями эмоциональных состояний без написания кода вручную
- Вывод: Rive — production-proven для персонажей в consumer apps
🎵 Spotify Wrapped 2025
- Реализован в Rive; дизайн отправляет в production интерактивную анимацию, код управляет данными
- Паттерн: «design ships interaction in Rive, code drives it with data» — именно то, что нам нужно
🤖 Notion AI — Спиннер-искры
- Визуал: анимированные искры/частицы при генерации текста
- Что работает: ощущение «творческой энергии», не агрессивное
- Минус: статичный, нет эмоциональных состояний
2. Rive.app — Детальный Разбор
2.1 Что такое Rive и зачем он нам
Rive — это инструмент для создания интерактивных, production-ready анимаций с встроенной логикой через State Machine. В отличие от Lottie (только воспроизведение заранее заданной анимации), Rive позволяет:
- Управлять переходами между состояниями в реальном времени
- Передавать данные из кода (амплитуда звука, состояние AI) прямо в дизайн
- Дизайнер работает в редакторе → разработчик подключает
.rivфайл → интерактивность работает «из коробки»
Ключевое преимущество для нашего случая: голосовая реактивность реализуется через Number input в State Machine — разработчик передаёт значение (0.0–1.0 от амплитуды микрофона), дизайн реагирует без написания анимационного кода.
2.2 Rive для iOS — Техническая Интеграция
Репозиторий: github.com/rive-app/rive-ios
- 780 ⭐ | MIT License | v6.20.3 (май 2026) | 239 релизов
Установка (Swift Package Manager — рекомендуется):
// Package.swift
dependencies: [
.package(url: "https://github.com/rive-app/rive-ios", from: "6.13.0")
]
Требования: iOS 14.0+, visionOS 1.0+, tvOS 16.0+, macOS 13.1+
Минимальная интеграция в SwiftUI (Legacy API — проще для начала):
import RiveRuntime
struct CharacterView: View {
var body: some View {
RiveViewModel(
fileName: "ai_companion",
stateMachineName: "EmotionMachine"
).view()
}
}
Продвинутая интеграция (новый runtime, Swift Concurrency):
import RiveRuntime
struct CharacterView: View {
@State private var riveView: RiveUIView?
var body: some View {
AsyncRiveUIViewRepresentable {
let worker = try await Worker()
let file = try await File(source: .local("ai_companion", Bundle.main), worker: worker)
return try await Rive(file: file)
}
}
}
Управление через State Machine (Data Binding):
// Передача амплитуды микрофона → анимация
let numberProp = viewModelInstance.numberProperty(fromPath: "audioAmplitude")!
numberProp.value = Float(microphoneAmplitude) // 0.0...1.0
// Изменение эмоционального состояния
let enumProp = viewModelInstance.enumProperty(fromPath: "emotionState")!
enumProp.value = "thinking" // или "speaking", "listening", "happy", "concerned"
2.3 State Machine в Rive — Как Работает
State Machine — это граф состояний анимации с переходами.
Для нашего персонажа:
[Entry] → [Idle/Breathing] ↔ [Listening] ↔ [Thinking] ↔ [Speaking] ↔ [Happy] ↔ [Concerned]
Типы inputs:
| Тип | Использование |
|---|---|
Boolean |
isListening, isSpeaking, isThinking |
Number |
audioAmplitude (0.0–1.0), emotionIntensity |
Trigger |
onHappy, onConcerned, onGreet |
Enum |
currentState (idle/listen/think/speak/happy/concerned) |
Settled State: автоматически останавливает рендеринг когда нет активных переходов → экономит CPU/батарею. Для idle-анимации = зацикленная бесконечная анимация, которая продолжает работать.
Playback управление:
simpleVM.pause() // заморозить на текущем кадре
simpleVM.play() // возобновить с текущей позиции
simpleVM.stop() // сброс к начальному состоянию
simpleVM.reset() // полный сброс state machine
2.4 Голосовая Реактивность: Как Именно
Схема реализации:
- AVAudioEngine (iOS) → получаем амплитуду микрофона в реальном времени
- Нормализуем:
amplitude = (rawValue + 160) / 160(или другой масштаб) - Передаём в Rive через Number property:
audioAmplitude = smoothedAmplitude - В Rive дизайнер привязывает это число к scale/radius/деформации blob
Код для получения амплитуды:
import AVFoundation
class MicrophoneMonitor: ObservableObject {
private var audioEngine = AVAudioEngine()
@Published var amplitude: Float = 0.0
func startMonitoring() {
let inputNode = audioEngine.inputNode
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { buffer, _ in
guard let channelData = buffer.floatChannelData else { return }
let frameLength = Int(buffer.frameLength)
let rms = sqrt(channelData[0][0..<frameLength].map { $0 * $0 }.reduce(0, +) / Float(frameLength))
DispatchQueue.main.async {
// Сглаживание (lerp) для избежания дёргания
self.amplitude = self.amplitude * 0.7 + min(rms * 10, 1.0) * 0.3
}
}
try? audioEngine.start()
}
}
В SwiftUI — связка:
struct CharacterContainer: View {
@StateObject private var mic = MicrophoneMonitor()
@State private var riveVM = RiveViewModel(fileName: "companion", stateMachineName: "Main")
var body: some View {
riveVM.view()
.onChange(of: mic.amplitude) { newValue in
riveVM.setInput("audioAmplitude", value: newValue)
}
}
}
2.5 Rive Pricing для Indie Разработчика
| Тариф | Цена | Что важно |
|---|---|---|
| Free | $0/мес | Редактор бесплатно, нельзя экспортировать .riv файлы для production |
| Cadet | $9/мес (до 3 сидений) | ✅ Экспорт .riv файлов, неограниченные файлы, все State Machine фичи |
| Voyager | $32/мес | Libraries, Embed URL hosting, до 25 сидений |
| Enterprise | $120/мес | Для компаний $10M+ выручки |
Вывод для indie: $9/мес (Cadet) — это всё что нужно для MVP и production. Free можно использовать для прототипирования. Дизайнер тоже работает на Cadet или тебе передаёт .riv файл.
2.6 Lottie vs Rive — Сравнение для Нашего Use Case
| Критерий | Lottie | Rive |
|---|---|---|
| Интерактивность | ❌ Только воспроизведение | ✅ State Machine, inputs, data binding |
| Голосовая реактивность | ❌ Невозможно нативно | ✅ Number input → real-time |
| Размер файла | ~50–200KB | ~20–100KB (векторный .riv) |
| Производительность iOS | Хорошая | Отличная (собственный рендерер на Metal) |
| Workflow дизайнер | After Effects → экспорт JSON | Rive Editor (браузер/десктоп) |
| Стоимость для дизайнера | AE нужен ($55/мес) | Rive Cadet $9/мес |
| Обучение разработчика | 1–2 часа | 4–8 часов |
| Эмоциональные состояния | Несколько файлов + код | 1 файл + state machine |
| Settled state | ❌ | ✅ Экономия CPU |
| Итог для нашего проекта | ❌ Не подходит | ✅ Единственный правильный выбор |
Вердикт: Lottie — для декоративных анимаций (иконки, сплэш-скрины). Rive — для интерактивных персонажей с состояниями. Наш use case = Rive без сомнений.
3. Четыре Концепта Персонажа
🟣 Концепт A: Дышащий Орб ⭐ РЕКОМЕНДУЕМЫЙ
Визуал: Сфера диаметром ~120–160pt, светящаяся изнутри, с мягким bloom-эффектом. Базовый цвет — глубокий индиго (#3D2B8F), с внутренним свечением меняющим оттенок по состоянию.
5 состояний:
| Состояние | Визуал | Цвет | Поведение |
|---|---|---|---|
| Idle/Breathing | Медленное расширение-сжатие (±8%), 4 сек цикл | Индиго → тёмно-синий | Почти незаметное «дыхание» |
| Listening | Лёгкая пульсация (синхронно с голосом), размер +голос/амплитуда | Синий → бирюзовый (#00C4CC) | Активная реакция на звук |
| Thinking | Медленное вращение внутренних частиц/градиента, ±5% размер | Индиго → фиолетовый (#7B4FD4) | Внутреннее движение, «обработка» |
| Speaking | Ритмичные волны-пульсы, согласованные с TTS | Тёплый фиолетовый (#9B59B6) | Лёгкие ряби от центра |
| Happy | Быстрое «прыжковое» расширение (+20%), возврат | Тёплый персиковый (#FF6B6B → оранжевый) | Burst-эффект |
| Concerned | Медленное сжатие (-10%), глубже цвет | Тёмно-синий (#1A237E) | Серьёзность, не пугающая |
Техническая реализация в Rive:
- Основная форма: эллипс с несколькими вложенными эллипсами (layered glow)
- Внутренний градиент: радиальный, управляется через Number input
colorShift - Размер: scale контролируется через
audioAmplitude+ дополнительные keyframe анимации для каждого состояния - Bloom/glow: Vector Feathering в Rive (доступен с 2025) — нативный, без растра
- State machine: 1 Boolean
isActive+ 1 NumberaudioAmplitude+ 1 EnumemotionState
SwiftUI реализация (если без Rive — чистый SwiftUI):
struct BreathingOrb: View {
@State private var isPulsing = false
@State private var audioAmplitude: CGFloat = 0
var emotionColor: Color = .indigo
var body: some View {
ZStack {
// Внешнее свечение
Circle()
.fill(emotionColor.opacity(0.15))
.frame(width: 200 + audioAmplitude * 40)
.blur(radius: 20)
// Средний слой
Circle()
.fill(
RadialGradient(
colors: [emotionColor.opacity(0.8), emotionColor],
center: .center, startRadius: 10, endRadius: 70
)
)
.frame(width: 130 + audioAmplitude * 30)
.scaleEffect(isPulsing ? 1.05 : 0.97)
// Внутренняя яркость
Circle()
.fill(Color.white.opacity(0.3))
.frame(width: 50)
.offset(x: -15, y: -15)
.blur(radius: 8)
}
.animation(.easeInOut(duration: 2).repeatForever(autoreverses: true), value: isPulsing)
.onAppear { isPulsing = true }
}
}
Эмоциональный тон: спокойствие, присутствие, безопасность. Пользователь ощущает, что рядом «кто-то» — но не человек, не робот. «Существо света».
Сложность реализации:
- DIY SwiftUI: 4/10 (можно сделать за день)
- Rive с дизайнером: 6/10 (1–2 недели работы дизайнера)
🟡 Концепт B: Поле Частиц
Визуал: 50–200 светящихся точек диаметром 2–6pt, формирующих разные паттерны в зависимости от состояния.
Состояния через паттерны:
- Idle: медленное дрейфование, как звёзды
- Listening: частицы притягиваются к центру, образуя «ухо»-форму
- Thinking: хаотичное кружение в определённой зоне
- Speaking: волнообразное движение от центра
- Happy: взрыв наружу + возврат
Реализация голосовой реактивности:
// SpriteKit или SwiftUI Canvas
// audioAmplitude → силовое поле, отталкивающее частицы
// Каждая частица: позиция = basePosition + sin(time + index) * amplitude * 20
Сложность:
- DIY SwiftUI Canvas/SpriteKit: 7/10
- Rive: 8/10 (частицы в Rive нетривиальны, лучше через Scripting/Luau)
- Metal: 5/10 при наличии знаний Metal Shaders
Плюсы: ощущение интеллекта, «нейронная сеть», уникально
Минусы: более сложная реализация, может отвлекать от рефлексии; плохо читается при нервозности пользователя
🟢 Концепт C: Флюидный Blob
Визуал: органическая морфирующая форма — как капля ртути или живая клетка. Постоянно деформируется, «перетекает».
Референсы в продуктах:
- iOS 17 Dynamic Island — blob-морфинг для уведомлений → пользователи полюбили
- Headspace «sleep sounds» анимации — флюидные формы воды
- Adobe Creative Cloud онбординг (2021) — морфирующие blob-переходы
Реализация:
Вариант 1 — SwiftUI Canvas + CGPath:
// Генерация blob через control points
func blobPath(points: [CGPoint], smoothing: CGFloat) -> Path {
// Catmull-Rom сплайны между точками
// audioAmplitude → смещение контрольных точек
}
Вариант 2 — Metal Shader (лучший результат):
// Метаболы (metaballs) — классическая техника для blob
// distance = sqrt(dx*dx + dy*dy)
// field += radius*radius / distance
// Если field > threshold → рисуем пиксель
Вариант 3 — Rive с mesh deformation:
- Rive поддерживает Meshes (деформация сетки) — дизайнер создаёт blob-форму, задаёт точки деформации, управляемые через inputs
- Сложность в Rive: 8/10
Голосовая реактивность: amплитуда → displacement map → blob «вздрагивает» синхронно с речью
Плюсы: максимальная «живость», визуально уникален, метафора «жидкого интеллекта»
Минусы: сложная реализация без дизайнера, может вызывать тревогу (нестабильная форма ≠ спокойствие)
Сложность: DIY Metal: 8/10, DIY SwiftUI: 6/10, Rive с дизайнером: 7/10
🔵 Концепт D: Аудио-Волна
Визуал: waveform-визуализация, реагирующая на голос — как старый Siri (iOS 7–9) или осциллограф.
Варианты формы:
- Классическая waveform (вертикальные полосы переменной высоты)
- Синусоида (гладкая волна)
- Круговая waveform (волна по окружности)
- «Сердцебиение» (EKG-стиль)
SwiftUI реализация (круговая):
struct AudioWaveformView: View {
var amplitudes: [Float] // массив ~64 значений
var color: Color = .purple
var body: some View {
Canvas { context, size in
let center = CGPoint(x: size.width/2, y: size.height/2)
let baseRadius: CGFloat = 60
var path = Path()
for (i, amp) in amplitudes.enumerated() {
let angle = Double(i) / Double(amplitudes.count) * 2 * .pi
let r = baseRadius + CGFloat(amp) * 40
let x = center.x + cos(angle) * r
let y = center.y + sin(angle) * r
if i == 0 { path.move(to: CGPoint(x: x, y: y)) }
else { path.addLine(to: CGPoint(x: x, y: y)) }
}
path.closeSubpath()
context.fill(path, with: .color(color.opacity(0.7)))
context.stroke(path, with: .color(color), lineWidth: 2)
}
}
}
Плюсы:
- Максимально простая реализация (DIY: 2/10)
- Мгновенная связь аудио → визуал понятна пользователю
- Ощущение «технологичности»
Минусы для психологического контекста:
- Холодный, технический — не тёплый
- Siri давно переехал от waveform именно потому что она не вызывала эмпатии
- Плохо передаёт «мышление» — только «говорение»/«слушание»
- Нет визуального способа показать «обеспокоенность» или «радость»
Вывод: Концепт D хорош как дополнительный элемент (показывать waveform голоса пользователя внизу экрана), но НЕ как основной персонаж.
4. Поиск Motion Дизайнера
4.1 Где Искать
| Платформа | Специфика | Ссылка |
|---|---|---|
| Rive Marketplace «For Hire» | Дизайнеры специально рекламируют Rive-навыки | rive.app/marketplace/for-hire |
| Twitter/X @rive_app | Официальный аккаунт; в ответах и RT часто появляются авторы | twitter.com/rive_app |
| Dribbble #rive | Фильтр по тегу; смотри работы со state machine видео | dribbble.com/tags/rive |
| Upwork | Поиск «Rive animation designer»; ~$30–80/час | upwork.com |
| Toptal | Топ 3% фрилансеров; $80–150/час; медленный онбординг | toptal.com |
| Discord Rive Community | #for-hire канал; сообщество ~15K человек | discord.com/invite/FGjmaTr |
| Behance | Поиск «Rive character animation»; не всегда указывают Rive явно | behance.net |
| «Rive motion designer iOS» → фильтр по навыкам | linkedin.com |
Самый быстрый путь: Rive Discord #for-hire + Rive Marketplace For Hire
4.2 Шаблон Брифа для Motion Дизайнера
## Проект: AI-компаньон для приложения психологической рефлексии
### Контекст
Мобильное приложение (iOS/Android) для ежедневной психологической рефлексии с AI-компаньоном.
Аудитория: взрослые 25–45 лет, работают со стрессом, ищут поддержку.
### Задача
Разработать абстрактного анимированного персонажа — визуальное лицо AI-компаньона.
**НЕ**: человек, робот, животное.
**ДА**: орб, blob, абстрактная форма — тёплая, живая, доверительная.
### Концепт (базовый)
[Концепт A: Дышащий орб] — светящаяся сфера ~140pt, с мягким bloom-эффектом.
Референсы: ChatGPT voice mode orb, Apple Siri (iOS 16), Headspace Andy (стиль — не копия).
### Состояния (5 обязательных + idle)
1. **Idle/Breathing** — медленное дыхание, базовый цвет (индиго/фиолетовый)
2. **Listening** — реактивный к амплитуде звука через Number input `audioAmplitude` (0.0–1.0)
3. **Thinking** — внутреннее движение, «обрабатываю»
4. **Speaking** — пульс/волны при TTS
5. **Happy/Positive** — тёплый burst
6. **Concerned/Serious** — сдержанность, глубокий цвет
### Технические требования
- **Инструмент**: Rive (обязательно)
- **Deliverable**: `.riv` файл с настроенной State Machine
- **State Machine inputs**:
- `audioAmplitude` (Number, 0.0–1.0) — голосовая реактивность
- `emotionState` (Enum: idle/listening/thinking/speaking/happy/concerned)
- **Размер артборда**: 300×300pt (векторный, масштабируемый)
- **Производительность**: файл должен работать в 60fps на iPhone 12 и новее
- Использовать Vector Feathering для glow (не PNG/растр)
### Что включает deliverable
- [ ] Концепт (2–3 варианта визуала) — для согласования
- [ ] Финальный `.riv` файл со state machine
- [ ] Короткое видео-демо всех состояний (GIF или MP4)
- [ ] Инструкция по inputs для разработчика (1 страница)
### Бюджет ориентировочно
$300–600 (уточняем после концепта)
### Сроки
Концепт: 3–5 дней
Финальный файл: 7–14 дней после согласования
### Контакт / Портфолио
Прошу показать примеры работ с Rive State Machine (не просто Lottie/AE).
4.3 Реалистичная Стоимость
| Уровень дизайнера | Профиль | Концепт + 5 состояний + .riv | Сроки |
|---|---|---|---|
| Junior Rive | Upwork, 1–2 года опыта | $150–300 | 10–21 день |
| Mid-level | Upwork/Dribbble, портфолио Rive | $300–600 ✅ sweet spot | 7–14 дней |
| Senior/Студия | Toptal, известные имена | $800–2000+ | 14–30 дней |
| Готовый шаблон | Marketplace + кастомизация | $0–50 + $100–200 dev time | 2–5 дней |
Реалистичная цена для MVP: $300–500 за полный пакет (концепт + 5 состояний + .riv файл)
4.4 Готовые Персонажи на Маркетплейсах
Rive Marketplace (rive.app/marketplace):
- Теги для поиска:
orb,blob,character,loader,mascot - Большинство файлов бесплатны для просмотра/ремикса с attribution
- Некоторые продаются за $5–30
Рекомендуемый поиск:
site:rive.app/community orb animationsite:rive.app/community blob character state machine
LottieFiles (для Lottie) — не подходит для нашего interactive use case, но можно найти вдохновение: lottiefiles.com/search?q=orb+ai+character
Другие источники готовых Rive файлов:
- awesome-rive: github.com/rive-app/awesome-rive — кураторский список
- Gumroad + поиск «Rive character»
- Creative Market + поиск «Rive animation»
5. DIY Вариант
5.1 Можно ли Без Дизайнера?
Да, и вот почему это разумно для TestFlight MVP:
- Для бета-тестирования важно проверить концепцию взаимодействия, а не полировку
- SwiftUI Canvas + TimelineView позволяет сделать «достаточно хороший» орб за 1–2 дня
- После валидации концепции → нанять дизайнера для production-версии
5.2 Минимальная Версия для TestFlight
Что должна уметь (MVP):
- Визуально отличаться в 3+ состояниях (idle, listening, speaking)
- Реагировать на амплитуду микрофона (пульс/размер)
- Плавные переходы между состояниями (withAnimation + ease)
- Работать в 60fps без прыжков
- Не выглядеть «сломанной» при любом сценарии
Что НЕ нужно для MVP:
- Профессиональный Rive-файл
- Все 6 эмоциональных состояний
- Идеальный bloom/glow
5.3 Полный SwiftUI Орб — Структура Кода
import SwiftUI
import AVFoundation
// MARK: - Состояния персонажа
enum CompanionState {
case idle, listening, thinking, speaking, happy, concerned
var color: Color {
switch self {
case .idle: return Color(hex: "#3D2B8F") // индиго
case .listening: return Color(hex: "#00C4CC") // бирюзовый
case .thinking: return Color(hex: "#7B4FD4") // фиолетовый
case .speaking: return Color(hex: "#9B59B6") // тёплый фиолетовый
case .happy: return Color(hex: "#FF6B6B") // персиковый
case .concerned: return Color(hex: "#1A237E") // тёмно-синий
}
}
var pulseSpeed: Double {
switch self {
case .idle: return 3.0
case .listening: return 1.5
case .thinking: return 2.0
case .speaking: return 0.8
case .happy: return 0.5
case .concerned: return 4.0
}
}
var baseScale: CGFloat {
switch self {
case .idle: return 1.0
case .listening: return 1.05
case .thinking: return 0.97
case .speaking: return 1.03
case .happy: return 1.15
case .concerned: return 0.92
}
}
}
// MARK: - Орб
struct CompanionOrbView: View {
var state: CompanionState
var audioAmplitude: Float // 0.0...1.0
@State private var isBreathing = false
@State private var rotationAngle: Double = 0
private let baseSize: CGFloat = 130
var body: some View {
let amplitudeBoost = CGFloat(audioAmplitude) * 35
let currentSize = baseSize * state.baseScale + amplitudeBoost
ZStack {
// Слой 3: дальнее свечение
Circle()
.fill(state.color.opacity(0.08))
.frame(width: currentSize + 70)
.blur(radius: 30)
// Слой 2: среднее свечение
Circle()
.fill(state.color.opacity(0.2))
.frame(width: currentSize + 30)
.blur(radius: 15)
// Слой 1: основной орб
Circle()
.fill(
RadialGradient(
colors: [
state.color.opacity(0.6),
state.color,
state.color.opacity(0.85)
],
center: .init(x: 0.35, y: 0.3),
startRadius: 5,
endRadius: currentSize / 2
)
)
.frame(width: currentSize, height: currentSize)
.scaleEffect(isBreathing ? 1.04 : 0.97)
// Внутренний блик (имитация 3D)
Ellipse()
.fill(
LinearGradient(
colors: [.white.opacity(0.4), .clear],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
.frame(width: currentSize * 0.45, height: currentSize * 0.25)
.offset(x: -currentSize * 0.12, y: -currentSize * 0.18)
.blur(radius: 4)
// Вращающийся внутренний элемент (для состояния "thinking")
if state == .thinking {
Circle()
.trim(from: 0, to: 0.3)
.stroke(state.color.opacity(0.5), lineWidth: 2)
.frame(width: currentSize * 0.6)
.rotationEffect(.degrees(rotationAngle))
}
}
.animation(
.easeInOut(duration: state.pulseSpeed).repeatForever(autoreverses: true),
value: isBreathing
)
.animation(.easeInOut(duration: 0.4), value: state)
.animation(.linear(duration: 0.05), value: audioAmplitude)
.onAppear {
isBreathing = true
withAnimation(.linear(duration: 2).repeatForever(autoreverses: false)) {
rotationAngle = 360
}
}
}
}
// MARK: - Контейнер с микрофоном
struct CompanionContainer: View {
@StateObject private var mic = MicrophoneMonitor()
@State var companionState: CompanionState = .idle
var body: some View {
VStack {
Spacer()
CompanionOrbView(state: companionState, audioAmplitude: mic.amplitude)
.frame(width: 220, height: 220)
Spacer()
}
.background(Color(hex: "#0D0D1A")) // тёмный фон
.onAppear { mic.startMonitoring() }
}
}
Оценка результата без дизайнера: 6.5/10 — выглядит профессионально для бета-тестирования при правильно подобранных цветах.
6. Сводная Таблица Концептов
| Критерий | A: Орб | B: Частицы | C: Blob | D: Waveform |
|---|---|---|---|---|
| Эмоциональное тепло | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ |
| DIY сложность | 4/10 | 7/10 | 6/10 | 2/10 |
| Голосовая реактивность | ✅ Отлично | ✅ Хорошо | ✅ Хорошо | ✅ Отлично |
| Rive реализация | 6/10 | 8/10 | 7/10 | 3/10 |
| Для психологии | ✅✅✅ | ✅✅ | ✅✅ | ⚠️ |
| Уникальность | Средняя | Высокая | Высокая | Низкая |
| Стоимость дизайнера | $300–500 | $400–700 | $400–600 | $150–300 |
7. ✅ Рекомендация и Следующие Шаги
Рекомендованный Концепт: A (Дышащий Орб) с элементами C (Blob)
Почему:
- Орб — самый доказанный паттерн (Siri, ChatGPT, Alexa) — пользователи уже знают этот «язык»
- Добавление slight fluid-деформации (±blob) делает его уникальным и «живым»
- Лучший баланс тепла + технологичности для психологического контекста
- Реалистичен для DIY MVP
- Хорошо масштабируется до профессиональной Rive-версии
Цветовая палитра:
- Base:
#3D2B8F(тёмный индиго) - Listening:
#00C4CC(бирюзовый) - Thinking:
#7B4FD4(фиолетовый) - Speaking:
#9B59B6 - Happy:
#FF6B6B - Concerned:
#1A237E - Background:
#0D0D1A(почти чёрный)
Путь 1: DIY для TestFlight (Рекомендую НАЧАТЬ ЗДЕСЬ)
Что делать:
- Реализовать SwiftUI орб из кода выше (1–2 дня)
- Подключить AVAudioEngine (1 день)
- Добавить 3 состояния: idle / listening / speaking (1 день)
- Запустить TestFlight бета, собрать отзывы (2 недели)
- Решить — нанимать дизайнера или нет
Стоимость: $0 (только время разработчика)
Срок до TestFlight: ~5–7 дней
Путь 2: Hire Motion Designer (После Валидации Концепции)
Когда нанимать: после того как бета подтвердит что персонаж нужен и работает
Где искать: Rive Discord #for-hire → Rive Marketplace for-hire → Upwork
Бюджет: $400–600 за полный пакет
Что получить: концепт (2–3 варианта) + .riv файл + state machine + инструкция
Конкретные шаги:
- Написать бриф по шаблону выше
- Разместить в Rive Discord #for-hire
- Попросить показать работы именно с Rive State Machine
- Начать с концепта ($50–100 за концепт) → подтвердить → финальный файл
Инструменты и Ресурсы
| Ресурс | Ссылка |
|---|---|
| Rive Editor (бесплатно) | editor.rive.app |
| Rive iOS Runtime | github.com/rive-app/rive-ios |
| Rive Docs iOS | rive.app/docs/runtimes/apple/apple |
| Rive Docs State Machine | rive.app/docs/runtimes/state-machines |
| Rive Community Discord | discord.com/invite/FGjmaTr |
| Rive Marketplace | rive.app/marketplace |
| awesome-rive | github.com/rive-app/awesome-rive |
| Видео: Build iOS App with Rive (DesignCode, 187K views) | youtube.com/watch?v=h4vyOz4Tztg |
| Видео: Build Interactive Characters in Rive (67K views) | youtube.com/watch?v=-vuQvvFiR8s |
| Видео: Glowing Jellyfish (blob референс) | youtube.com/watch?v=4oH0jV-L-dU |
| Видео: Rive State Machine Tutorial | youtube.com/watch?v=oDhdGmXco00 |
Документ создан агентом исследования. Обновить после TestFlight бета (2 недели).