Add personality system with emote variations and animations

- Rotating optimal faces with paired animations (breathing, floating, bouncing, swaying)
- Occasional idle expressions (winks/blinks) with 15% chance
- Recovery celebration emote with bounce animation
- Connection lost state with searching animation
- Face rotation every 5 minutes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-02 21:31:27 -06:00
parent 11896919e4
commit af4ccb9a35
2 changed files with 160 additions and 4 deletions

View File

@@ -4,6 +4,7 @@ A lightweight event broker that manages priority-based system status.
"""
import json
import random
import threading
import time
from datetime import datetime
@@ -16,6 +17,22 @@ ROOT_DIR = Path(__file__).parent
# Configuration
STATUS_FILE = Path(__file__).parent / "status.json"
DEFAULT_NOTIFY_TTL = 10 # Default TTL for Priority 3 (Notify) events
CELEBRATION_DURATION = 5 # Seconds to show celebration after recovery
# Emote variations with paired animations
OPTIMAL_EMOTES = [
("( ^_^)", "breathing"), # calm, content
("( ᵔᴥᵔ)", "floating"), # dreamy
("(◕‿◕)", "bouncing"), # cheerful
("( ・ω・)", "swaying"), # curious
("( ˘▽˘)", "breathing"), # cozy
]
IDLE_EMOTES = [
("( -_^)", "blink"), # wink
("( ^_~)", "blink"), # wink
("( ᵕ.ᵕ)", "blink"), # blink
]
CELEBRATION_EMOTE = ("\\(^o^)/", "celebrating")
# Priority definitions
PRIORITY_CONFIG = {
@@ -29,9 +46,20 @@ PRIORITY_CONFIG = {
events_lock = threading.Lock()
active_events = {} # id -> {priority, message, timestamp, ttl}
# State tracking for personality
previous_priority = 4
celebrating_until = 0
last_emote_change = 0
current_optimal_emote = OPTIMAL_EMOTES[0][0]
current_optimal_animation = OPTIMAL_EMOTES[0][1]
def get_current_state():
"""Determine current state based on active events."""
global previous_priority, celebrating_until, last_emote_change, current_optimal_emote, current_optimal_animation
now = time.time()
with events_lock:
if not active_events:
priority = 4
@@ -45,11 +73,38 @@ def get_current_state():
]
config = PRIORITY_CONFIG[priority]
emote = config["emote"]
animation = config["animation"]
color = config["color"]
# Check for recovery (was bad, now optimal)
if priority == 4 and previous_priority < 4:
celebrating_until = now + CELEBRATION_DURATION
previous_priority = priority
# Handle optimal state personality
if priority == 4:
if now < celebrating_until:
# Celebration mode
emote, animation = CELEBRATION_EMOTE
else:
# Rotate optimal emotes every 5 minutes, occasional idle expression
if now - last_emote_change > 300:
last_emote_change = now
# 15% chance of an idle expression (wink/blink)
if random.random() < 0.15:
current_optimal_emote, current_optimal_animation = random.choice(IDLE_EMOTES)
else:
current_optimal_emote, current_optimal_animation = random.choice(OPTIMAL_EMOTES)
emote = current_optimal_emote
animation = current_optimal_animation
return {
"current_state": config["name"].lower(),
"active_emote": config["emote"],
"color": config["color"],
"animation": config["animation"],
"active_emote": emote,
"color": color,
"animation": animation,
"message": config["name"] if priority == 4 else f"{config['name']} state active",
"active_events": sorted(events_list, key=lambda x: x["priority"]),
"last_updated": datetime.now().isoformat(timespec="seconds"),