rebreak-monorepo/docs/RIVE_ANIMATOR_BRIEF.md
chahinebrini 5d6c322129 wip: KeyboardAwareSheet migrations + Snake/Tetris UI + iron.png + useMe live-update
Sheets via neuer KeyboardAwareSheet-Composable (in Modal pattern, auto-grow
mit Tastatur, paddingBottom-Lift): EditMail, AddDomain, CreateRoom, ConnectMail.
GameOverScreen behält Spring-Slide-In, nutzt RN Keyboard.addListener für Lift.

- KeyboardAwareSheet.tsx — universal modal with sheet-grow + keyboard-padding
- react-native-keyboard-controller installiert + KeyboardProvider in Root
- Snake: time + ScoreProgressBar + useSnakeSounds (haptic, audio TODO)
- Tetris: title weg, Buttons zentriert, kein Pressable mit style-fn
- DPad-Buttons 60→48, more bg, no scale
- useMe: pub-sub listener pattern für app-weite avatar/nickname-Updates
- dm.tsx: resolveAvatar wrap (iron.png-Warning)
- Mail-error-humanizer + locales

Recovery-Doc-Update in docs/internal/RECOVERY_LOG_2026-05-10.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 23:59:25 +02:00

159 lines
9.5 KiB
Markdown

# Rive Animator Brief — Lyra Avatar Emotion States
**Ready-to-publish — copy section between the dividers below into your job-post on Dribbble / Fiverr / Twitter / Rive Discord.**
---
## 🎯 Project: Rebreak — Lyra Avatar Animation
I'm hiring a Rive-animator to extend **Lyra**, the AI-companion of **Rebreak** — a recovery app for people working through gambling addiction (German market, planned DiGA-listing in healthcare).
**Critical context:** This is a sensitive recovery-app, NOT a playful game. Lyra is a warm, present companion — never cute-mascot, never childish, never dramatic. Subtle > exaggerated.
**Budget: $100 USD, ~1 week target.** Self-qualify before applying.
## What I have (current `.riv`)
- File: `lyra-avatar.riv` (264 KB) — will be shared after engagement-confirmation
- **Artboard name:** `Artboard`
- **State machine name:** `State Machine 1`, default state `idle`
- **Existing animation timelines** (extracted via `strings`):
- `Idle Loop` — wired as `idle`
- `idle to Pose 1` + `Pose 1 loop` — wired as `happy` (2-phase: app manually switches via 900ms JS-timer)
- `01 Wave 1` — wired as `empathy`
- `01 Wave 2` — exists, NOT wired (orphan)
- `WALK` — placeholder, currently aliased as `thinking` (please replace with proper thinking-pose animation)
- `Kedip` (Indonesian "blink") — orphan from template
- **Runtime:** `rive-react-native ^9.0.1` (export against this compatible Rive editor version)
- **Avatar usage:** appears at 40px (small list), 112px (chat-header), 160px (onboarding hero) — **must read clearly even at 40px**
## ⚠️ Critical naming contract — do NOT rename existing names
The React code calls timelines **directly by name** (not via state-machine inputs). If you rename a timeline, the app silently breaks (no animation plays, no error). This means:
- **Keep:** `Artboard` artboard, `State Machine 1` SM-name, `idle` default-state, `Idle Loop` timeline name
- **New emotion-states must use exactly these timeline names** (snake_case): `sad`, `joy`, `confusion`, `calm`, `surprise`, `listening`, `thinking` (replacing `WALK`)
- **For multi-phase emotions** (e.g. dramatic intro → loop): use `<state> intro` + `<state> loop` pattern, just like existing `idle to Pose 1` + `Pose 1 loop`
- **Bonus** (+$X if you propose): expose state-machine inputs (`SetEmotion` enum-trigger) so we can transition imperatively. Optional — named-timelines remain the primary contract.
## Deliverables — emotion states
You'll add these to the existing state-machine. Total: **6 new states + 1 placeholder-replacement (`thinking`)**.
### Tier 1 — must-have (4 states, baseline budget)
| Internal name (timeline) | Trigger in app | Eyes | Brow | Mouth | Body |
|---|---|---|---|---|---|
| **`thinking`** (REPLACE `WALK`) | LLM is generating response | look up-and-to-side, slow blink | one slightly raised | gently closed, slight pursed | finger-near-temple pose if possible, head tilt ~5° |
| **`listening`** | User mid-typing OR voice-recording | open, attentive, natural blink | neutral relaxed | gently closed, micro-Mona-Lisa upturn | subtle head nod every ~3s |
| **`calm`** | Breathing exercise / meditation active | half-closed | neutral relaxed | slight serene smile | very slow up/down breathing loop (~4s cycle to match 4-7-8 breathing pace) |
| **`sad`** | User describes loss/relapse/shame | softened, slight downcast, lower lid raised | inner-up, slight angle | closed, neutral or micro-downturn | tiny head tilt down (~5°), slow breathing |
### Tier 2 — nice-to-have (2-3 more states, push budget if you can)
| Internal name (timeline) | Trigger in app | Visual direction |
|---|---|---|
| **`joy`** | Streak milestone, big celebration | bigger smile than `happy` (warmer not goofy), small head bounce on intro then settle |
| **`confusion`** | Lyra needs clarification | one brow raised, slight squint, head tilt ~10° to one side |
| **`surprise`** | Unexpected user input | wide-open eyes (brief), both brows raised, small "o" mouth, quick head pull-back micro on intro then settle |
### Skip these (anti-patterns for recovery use-case)
-`angry` / `frustrated` — never from coach
-`shocked` / `horror` — too dramatic for trauma-context
- ❌ Cute-mascot expressions (winks, tongue-out, hearts in eyes)
- ❌ Heavy bone-rigs / particles — runtime cost too high
## Visual style guidelines
- **Match existing Lyra-look** (extract palette + line-weight from the `.riv` you'll receive)
- **Subtle is better** — these animations play during emotional moments, they should *support* not *demand* attention
- **Loop-friendly** — `idle`, `calm`, `listening` should breathe naturally, no pop on loop boundary
- **Smooth transitions** — prefer 200-400ms crossfades over hard cuts. Especially: `empathy → idle → happy` should never feel jarring (route through idle, never direct jump from negative to positive)
- **Readability at 40px** — exaggerate eye/brow shapes slightly, avoid mouth-only emotion (mouth is too small at 40px to carry expression)
## Technical Requirements
- **Output: ONE `.riv` file** named exactly `lyra-avatar.riv` (replaces current file)
- **Single artboard, single state-machine** — preserve existing structure
- **Rive editor version**: 2024.x (compatible with `rive-react-native ^9.0.1`)
- **Performance**: 60 fps target on mid-range Android (Pixel 5-class)
- **File-size**: ≤500KB (current 264KB, want headroom for new states)
- **Loop-cycle precision**: `calm` should be ~4 seconds (we sync app-side to user's 4-7-8 breathing exercise)
## Bonus task (optional, +scope)
Existing `happy` uses a 2-phase manual switch via 900ms JS-timeout — clunky. **If you can fix this so it loops cleanly inside the `.riv` itself** (intro auto-blends into loop without app-side coordination), that's worth +$X.
## Timeline + Budget
- **$100 USD flat**, paid: 50% on first-draft approval, 50% on final delivery
- **1 week** from brief-confirmation
- **Milestones**:
1. Day 0: brief-confirm + you receive `.riv` file + answers to your questions
2. Day 2-3: first draft of 1-2 states for visual-direction approval (style-confirm)
3. Day 4-6: remaining states + 1 round of revisions
4. Day 7: final delivery
## Deliverables you provide
1. **`lyra-avatar.riv`** — replaces existing file
2. **Short README** (1 page max):
- List of all timeline-names + when each plays
- Any limitations or known issues
- State-machine diagram (simple)
3. **Source-file** (Rive editor `.rev` or equivalent) for future edits
4. **Optional bonus**: short demo-video (15-30 sec) showing all states cycling — earns trust
## Questions to ask BEFORE starting (please answer in your application)
1. Can I use the current `.riv` as a base and add states, or do you want a clean rebuild?
2. Confirm Rive runtime version (`rive-react-native ^9.0.1`) — compatible with your export?
3. Should I also fix the existing `happy` 2-phase JS-timer (auto-blend in `.riv` instead)?
4. For the German market: any culture-specific gestures to avoid?
5. Any brand-colors / hex-codes I must match?
6. Audio cues or visual-only?
7. Do you have Figma / brand-guide I should reference?
## What I value in your work
- Restraint over flashiness
- Clean state-machine architecture (other devs may extend later)
- Honest communication if scope is too tight for budget — happy to scope down to 4 states (Tier 1 only)
- Async-first (Slack-like / email / Discord-DM)
## How to apply
Send me:
1. Link to **Rive portfolio** (not Lottie, not After-Effects — actual `.riv` work)
2. **Confirmation you've read this brief** (so I know it's not auto-applied)
3. Your suggested approach: extend existing state-machine OR rebuild?
4. Your answers to the 7 questions above
Looking forward to working together.
---
**End of brief — copy everything above into your job-post.**
## How to use this brief (internal — not for animator)
1. **Vor dem Senden** alle `[Platzhalter]`-Stellen (insbesondere Communication-Channel falls du das spezifizieren willst) ausfüllen
2. **Aktuelle `.riv` mitschicken** — Animator braucht sie als Style-Referenz + State-Machine-Setup
3. **Klarstellen**: Emotion-Namen in der Tabelle sind **Code-Contracts** und müssen exakt so im Rive-File heißen — sonst muss React-Code refactored werden
4. **Vor Vergabe** 2-3 Animator-Portfolios checken — suche „warm/subtle character"-style, NICHT nur knallige Logo-Animationen
5. **Nach Erhalt der ersten Draft** auf echtem Android-Mid-Range-Gerät testen (Pixel 5 oder älter), nicht nur iOS-Simulator
6. **Wo publishen** (in Reihenfolge der Wahrscheinlichkeit):
- Rive Discord (https://rive.app/community → Discord) — Rive-spezialisierte Animatoren, keine LottieFiles-Refugees
- Twitter `#RiveAnimation` hashtag + DMs an Animator-Portfolios die du gut findest
- Fiverr „Rive animator" custom-offers ($30-150 typische Gigs)
- Dribbble „Hiring" section — gemischte Quality, mehr Style-fokus
7. **Wenn `.riv` ankommt**: drag in `apps/rebreak-native/assets/lyra-avatar.riv` (overwrite), commit, fertig. Code ist schon flexibel (RiveAvatar accepts any state-name nach Task #39 component-flex).
## Sources / Internal-Files
- Brief-Audit: `apps/rebreak-native/components/RiveAvatar.tsx` (lines 42-51 — Emotion-API contract)
- Existing `.riv`: `apps/rebreak-native/assets/lyra-avatar.riv` (264 KB)
- Plugin: `apps/rebreak-native/plugins/with-rive-asset-android.js` (Android raw-resource auto-mirror)
- Trigger-context: `apps/rebreak-native/app/lyra.tsx` (lines 37-44, 306-323), `apps/rebreak-native/app/urge.tsx`, `apps/rebreak-native/lib/lyraResponse.ts:57-61` (existing `detectEmotion()`)