File size: 5,470 Bytes
76cd9e7
29c325a
 
 
 
 
 
d8d4968
f093097
76cd9e7
b52ebca
d8d4968
 
b52ebca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
---
title: Reachy Mini Simple Visual Novel
emoji: 🤖
colorFrom: blue
colorTo: purple
sdk: gradio
pinned: false
app: app.py
python_version: 3.12
---
## Visual Novel Demo
- Install `uv`
- Run `uv run python app.py`.

### Features
- Register characters with sprite URLs or inline SVG data-URIs (see `create_sprite_data_url`).
- Toggle simple idle animation per character (set `animated=True`) or point to GIF/WebP assets for full animation.
- Change backgrounds between scenes.
- Show, hide, and move characters between left/center/right anchors.
- Display narration or speaker dialogue in a speech-bubble overlay anchored to the scene.
- Navigate forward/backward through the story timeline.
- Opt-in webcam overlay per scene: call `builder.set_camera(True|False)` to show or hide the FastRTC stream alongside your story.
- Voice sandbox: record or upload microphone audio, forward it to a placeholder AI companion, and hear a synthetic confirmation tone back.
- Dynamixel control (Web Serial): connect over serial to XL330 servos and send goal positions directly from the browser—no Python SDK needed.
- **Reachy Mini robot control (WebSocket)**: connect to a Reachy Mini robot server and send real-time pose commands for head position, orientation, body yaw, and antennas.
- Per-scene toggles: show/hide camera, voice, motor, and robot controls with `set_camera`, `set_voice`, `set_motors`, and `set_robot`.

#### Customizing sprites
- Replace the SVG data-URIs in `build_sample_story()` with your own URLs (PNG/GIF/WebP).
- For animated sprites, provide an animated GIF/WebP URL and set `animated=True` to also enable the floaty idle motion.
- If you need frame-based animation control, extend `CharacterDefinition` with additional fields (e.g., `animation_frames`) and update `render_scene()` accordingly.

#### Camera widget
- Grant permission when prompted; the browser's default camera is streamed with FastRTC (`WebRTC` component).
- Scenes control whether the webcam appears. If a scene doesn't request it, you'll see a friendly notice instead of the stream.
- Browsers typically require HTTPS (or `http://localhost`) plus user permission before the stream can start; if the feed doesn’t appear, reload after granting access.

#### Voice sandbox
- Scenes decide whether voice capture shows up. Call `builder.set_voice(True|False)` per scene; when disabled, the audio UI hides completely.
- Use the **Voice & Audio Agent** accordion (when visible) to record or upload a clip; hit **Send to voice agent** to hand it to the (placeholder) AI hook.
- The app echoes your recording for playback and emits a synthetic tone to represent an AI voice. Replace `process_voice_interaction()` in `main.py` with real ASR/LLM/TTS calls to integrate your model stack.
- Default prompt text gives the agent scene context; edit it freely.

#### Dynamixel XL330 control
- The control panel lives entirely in the browser using the Web Serial API (Chrome/Edge on desktop). When prompted, select the USB/serial adapter attached to your Dynamixel bus.
- Choose baud, motor ID, and goal angle in the **Dynamixel XL330 Control** panel; click **Connect serial** (triggers the browser port picker) then **Send goal**. Use **Torque on/off** to toggle torque.
- Commands write Protocol 2.0 registers: torque enable (64) and goal position (116, 4 bytes). Angles 0–360° map to 0–4095 ticks.
- Frontend code lives in `web/dxl_webserial.js` and is loaded via `file=web/dxl_webserial.js`, mirroring the structure of `feetech.js`.

#### Reachy Mini robot control
- Connect to a Reachy Mini robot via WebSocket for real-time pose control during story scenes.
- **Requirements**: A running Reachy Mini server at `localhost:8000` with WebSocket endpoint `/api/move/ws/set_target`.
- The connection status is shown in the robot control panel with a color-coded indicator (🔴 disconnected / 🟢 connected).
- **Enable in scenes**: Call `builder.set_robot(True)` to show the robot control widget for specific scenes.
- **Send poses from story**: Use `builder.send_robot_pose()` to command the robot when a scene is displayed:
  ```python
  builder.send_robot_pose(
      head_x=0.0, head_y=0.0, head_z=0.02,  # Head position in meters
      head_roll=0.0, head_pitch=-0.1, head_yaw=0.0,  # Head orientation in radians
      body_yaw=0.0,  # Body rotation in radians
      antenna_left=-0.2, antenna_right=0.2  # Antenna positions in radians
  )
  ```
- WebSocket automatically connects when the widget becomes visible and reconnects if disconnected.
- Poses are sent automatically when navigating to scenes with robot commands (similar to motor commands and audio).

Edit `main.py` to customize `build_sample_story()` or create your own builder logic with `VisualNovelBuilder`.

### Using Custom Assets

Place your files in the `assets/` directory:
- `assets/backgrounds/` - Background images (1200x800 recommended)
- `assets/sprites/` - Character sprites (400x800 recommended, PNG with transparency)
- `assets/audio/` - Audio files (WAV, MP3, etc.)

Then use the helper functions in your story:

```python
from engine import background_asset, sprite_asset, audio_asset

builder.set_background(background_asset("my_background.png"), label="My Scene")

builder.set_characters([
    CharacterDefinition(
        name="Hero",
        image_url=sprite_asset("hero.png"),
        animated=False
    ),
])

# Play audio when scene is displayed
builder.play_sound(audio_asset("my_sound.wav"))
```