Skip to content

Commit 4a41ade

Browse files
authored
feat(expressive_eyes): Add new ExpressiveEyes component (#587)
* feat(expressive_eyes): Added new `ExpressiveEyes` component * fleshing out functionality to support multiple drawing styles and work with other hardware * replace eyebrow triangles with eyebrow line * minor cleanup * update example to go into random mode after test * finalizing code and adding docs / ci * fix doc * add console output * readme: update * address sa * fix sa * simplify config * fix animation state tracking to improve blending between states; flesh out some more of the expressions * doc: update * fix sa * fix sa * readme: update * remove unnecessary drawer readme * replace with libfmt formatting * cleanup * ensure wink states are blended like the rest for smooth transitions
1 parent 0dc9540 commit 4a41ade

20 files changed

+1801
-0
lines changed

.github/workflows/build.yml

100644100755
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ jobs:
7373
target: esp32s3
7474
- path: 'components/event_manager/example'
7575
target: esp32
76+
- path: 'components/expressive_eyes/example'
77+
target: esp32s3
7678
- path: 'components/file_system/example'
7779
target: esp32
7880
- path: 'components/filters/example'

.github/workflows/upload_components.yml

100644100755
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ jobs:
5959
components/esp-box
6060
components/esp32-timer-cam
6161
components/event_manager
62+
components/expressive_eyes
6263
components/file_system
6364
components/filters
6465
components/format
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
idf_component_register(
2+
INCLUDE_DIRS "include"
3+
SRC_DIRS "src"
4+
REQUIRES base_component
5+
)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Expressive Eyes Component
2+
3+
[![Badge](https://components.espressif.com/components/espp/expressive_eyes/badge.svg)](https://components.espressif.com/components/espp/expressive_eyes)
4+
5+
The `ExpressiveEyes` component provides animated expressive eyes for displays
6+
using simple blob shapes. Eyes can blink, look around, change expression, and
7+
display various emotions with smooth animations.
8+
9+
The component uses a callback-based drawing system, allowing you to implement
10+
custom renderers for different display types and visual styles.
11+
12+
https://github.com/user-attachments/assets/966f5e63-aeb8-4fc3-b915-c4936fee7a1f
13+
14+
## Features
15+
16+
- Multiple expressions (happy, sad, angry, surprised, neutral, sleepy, bored, wink_left, wink_right)
17+
- Smooth eye movement with look_at positioning
18+
- Automatic blinking with configurable intervals
19+
- Optional pupils with physics-based movement
20+
- Eyebrows and cheeks for enhanced expressions
21+
- Smooth expression transitions with blending
22+
- Customizable colors and sizes
23+
- Frame-based animation system
24+
25+
<table>
26+
<tr>
27+
<td>happy <img alt="image" src="https://github.com/user-attachments/assets/65f3afd4-fa4e-4100-9269-09b08300d37d" /></td>
28+
<td>sad <img alt="image" src="https://github.com/user-attachments/assets/d3df6898-dae4-4884-b72a-81a5c5a371ed" /></td>
29+
</tr>
30+
<tr>
31+
<td>angry <img alt="image" src="https://github.com/user-attachments/assets/43e54326-8da3-4d6b-8696-66fb85d2675c" /></td>
32+
<td>surprised <img alt="image" src="https://github.com/user-attachments/assets/a78b289c-7383-4b92-8651-bdc843b08bf7" /></td>
33+
</tr>
34+
<tr>
35+
<td>sleepy <img alt="image" src="https://github.com/user-attachments/assets/b891e260-97dd-4cce-9d80-2300816b6e79" /></td>
36+
<td>bored <img alt="image" src="https://github.com/user-attachments/assets/cc955086-bb69-41da-becc-80584b0af5c0" /></td>
37+
</tr>
38+
<tr>
39+
<td>wink left <img alt="image" src="https://github.com/user-attachments/assets/a1dde472-2bfa-480f-8a87-4deccd3b96b9" /></td>
40+
<td>wink right <img alt="image" src="https://github.com/user-attachments/assets/d92f8602-f287-441b-9612-50210be5831a" /></td>
41+
</tr>
42+
<tr>
43+
<td>looking left <img alt="image" src="https://github.com/user-attachments/assets/504d90a8-2125-45f7-8eeb-44ca6aa05cba" /></td>
44+
<td>looking right <img alt="image" src="https://github.com/user-attachments/assets/58626990-37cf-43d0-a8a6-e5ed01bd8b7c" /></td>
45+
</tr>
46+
<tr>
47+
<td>looking up <img alt="image" src="https://github.com/user-attachments/assets/1765eb2d-7c29-44c9-bbed-658af2ccabd4" /></td>
48+
<td>looking down <img alt="image" src="https://github.com/user-attachments/assets/65c19bb7-e8c4-4cee-93ba-a5be96cb2df7" /></td>
49+
</tr>
50+
</table>
51+
52+
## Example
53+
54+
The [example](./example) demonstrates the expressive eyes component with two
55+
different drawer implementations (full-featured realistic eyes and monochrome
56+
blue eyes) running on various ESP32 display boards.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# The following lines of boilerplate have to be in your project's CMakeLists
2+
# in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.20)
4+
5+
set(ENV{IDF_COMPONENT_MANAGER} "0")
6+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
7+
8+
# add the component directories that we want to use
9+
set(EXTRA_COMPONENT_DIRS
10+
"../../../components/"
11+
)
12+
13+
set(
14+
COMPONENTS
15+
"main esptool_py expressive_eyes display task esp-box matouch-rotary-display ws-s3-touch"
16+
CACHE STRING
17+
"List of components to include"
18+
)
19+
20+
project(expressive_eyes_example)
21+
22+
set(CMAKE_CXX_STANDARD 20)
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# Expressive Eyes Example
2+
3+
This example demonstrates animated expressive eyes on various ESP32 display
4+
boards. It showcases different expressions, eye movements, and includes a
5+
continuous random demo mode perfect for a desk display.
6+
7+
<table>
8+
<tr>
9+
<td>happy <img alt="image" src="https://github.com/user-attachments/assets/65f3afd4-fa4e-4100-9269-09b08300d37d" /></td>
10+
<td>sad <img alt="image" src="https://github.com/user-attachments/assets/d3df6898-dae4-4884-b72a-81a5c5a371ed" /></td>
11+
</tr>
12+
<tr>
13+
<td>angry <img alt="image" src="https://github.com/user-attachments/assets/43e54326-8da3-4d6b-8696-66fb85d2675c" /></td>
14+
<td>surprised <img alt="image" src="https://github.com/user-attachments/assets/a78b289c-7383-4b92-8651-bdc843b08bf7" /></td>
15+
</tr>
16+
<tr>
17+
<td>sleepy <img alt="image" src="https://github.com/user-attachments/assets/b891e260-97dd-4cce-9d80-2300816b6e79" /></td>
18+
<td>bored <img alt="image" src="https://github.com/user-attachments/assets/cc955086-bb69-41da-becc-80584b0af5c0" /></td>
19+
</tr>
20+
<tr>
21+
<td>wink left <img alt="image" src="https://github.com/user-attachments/assets/a1dde472-2bfa-480f-8a87-4deccd3b96b9" /></td>
22+
<td>wink right <img alt="image" src="https://github.com/user-attachments/assets/d92f8602-f287-441b-9612-50210be5831a" /></td>
23+
</tr>
24+
<tr>
25+
<td>looking left <img alt="image" src="https://github.com/user-attachments/assets/504d90a8-2125-45f7-8eeb-44ca6aa05cba" /></td>
26+
<td>looking right <img alt="image" src="https://github.com/user-attachments/assets/58626990-37cf-43d0-a8a6-e5ed01bd8b7c" /></td>
27+
</tr>
28+
<tr>
29+
<td>looking up <img alt="image" src="https://github.com/user-attachments/assets/1765eb2d-7c29-44c9-bbed-658af2ccabd4" /></td>
30+
<td>looking down <img alt="image" src="https://github.com/user-attachments/assets/65c19bb7-e8c4-4cee-93ba-a5be96cb2df7" /></td>
31+
</tr>
32+
</table>
33+
34+
Videos:
35+
36+
https://github.com/user-attachments/assets/966f5e63-aeb8-4fc3-b915-c4936fee7a1f
37+
38+
## How to use example
39+
40+
### Hardware Required
41+
42+
This example can be configured to run on the following dev boards:
43+
- ESP32-S3-BOX / ESP32-S3-BOX-3
44+
- MaTouch Rotary Display
45+
- WS-S3-Touch
46+
47+
### Configure the project
48+
49+
```
50+
idf.py menuconfig
51+
```
52+
53+
Navigate to `Expressive Eyes Example Configuration` to:
54+
- Select your board
55+
- Choose drawing method (Full Featured or Monochrome Blue)
56+
57+
### Build and Flash
58+
59+
Build the project and flash it to the board, then run monitor tool to view serial output:
60+
61+
```
62+
idf.py -p PORT flash monitor
63+
```
64+
65+
(Replace PORT with the name of the serial port to use.)
66+
67+
(To exit the serial monitor, type ``Ctrl-]``.)
68+
69+
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
70+
71+
## Example Breakdown
72+
73+
The example has three phases:
74+
75+
### 1. Expression Showcase
76+
77+
Cycles through all available expressions (3 seconds each):
78+
- Neutral
79+
- Happy
80+
- Sad
81+
- Angry
82+
- Surprised
83+
84+
### 2. Look Direction Demo
85+
86+
Demonstrates the look_at functionality by looking in different directions (1.5 seconds each):
87+
- Left
88+
- Right
89+
- Up
90+
- Down
91+
- Center
92+
93+
### 3. Random Demo Mode
94+
95+
Enters continuous random demo mode for engaging desk display:
96+
- **Natural behavior**: Mostly stays neutral with occasional emotional expressions
97+
- **Random looking**: Eyes look in random directions every 2-6 seconds
98+
- **Expression changes**: Randomly changes expression every 5-15 seconds
99+
- 50% neutral (most common)
100+
- 20% happy
101+
- 10% surprised
102+
- 10% sad
103+
- 10% angry
104+
- **Automatic blinking**: Eyes blink naturally at random intervals
105+
106+
The random demo mode runs indefinitely, making it perfect for a continuous desk display.
107+
108+
## Drawer Implementations
109+
110+
The example includes two drawer implementations:
111+
112+
### Full Featured Drawer
113+
- White eye background with black pupils
114+
- Eyebrows drawn as rotated lines with rounded caps
115+
- Cheeks for emotional expressions
116+
- Respects LVGL theme background color
117+
118+
### Monochrome Blue Drawer
119+
- Electric blue (#00BFFF) eyes on black background
120+
- No pupils (solid colored eyes)
121+
- Minimalist aesthetic perfect for sci-fi interfaces
122+
- Black eyebrows and cheeks
123+
124+
See [README_DRAWERS.md](./main/README_DRAWERS.md) for details on creating custom drawer implementations.
125+
126+
## Example Output
127+
128+
<table>
129+
<tr>
130+
<td>happy <img alt="image" src="https://github.com/user-attachments/assets/65f3afd4-fa4e-4100-9269-09b08300d37d" /></td>
131+
<td>sad <img alt="image" src="https://github.com/user-attachments/assets/d3df6898-dae4-4884-b72a-81a5c5a371ed" /></td>
132+
</tr>
133+
<tr>
134+
<td>angry <img alt="image" src="https://github.com/user-attachments/assets/43e54326-8da3-4d6b-8696-66fb85d2675c" /></td>
135+
<td>surprised <img alt="image" src="https://github.com/user-attachments/assets/a78b289c-7383-4b92-8651-bdc843b08bf7" /></td>
136+
</tr>
137+
<tr>
138+
<td>sleepy <img alt="image" src="https://github.com/user-attachments/assets/b891e260-97dd-4cce-9d80-2300816b6e79" /></td>
139+
<td>bored <img alt="image" src="https://github.com/user-attachments/assets/cc955086-bb69-41da-becc-80584b0af5c0" /></td>
140+
</tr>
141+
<tr>
142+
<td>wink left <img alt="image" src="https://github.com/user-attachments/assets/a1dde472-2bfa-480f-8a87-4deccd3b96b9" /></td>
143+
<td>wink right <img alt="image" src="https://github.com/user-attachments/assets/d92f8602-f287-441b-9612-50210be5831a" /></td>
144+
</tr>
145+
<tr>
146+
<td>looking left <img alt="image" src="https://github.com/user-attachments/assets/504d90a8-2125-45f7-8eeb-44ca6aa05cba" /></td>
147+
<td>looking right <img alt="image" src="https://github.com/user-attachments/assets/58626990-37cf-43d0-a8a6-e5ed01bd8b7c" /></td>
148+
</tr>
149+
<tr>
150+
<td>looking up <img alt="image" src="https://github.com/user-attachments/assets/1765eb2d-7c29-44c9-bbed-658af2ccabd4" /></td>
151+
<td>looking down <img alt="image" src="https://github.com/user-attachments/assets/65c19bb7-e8c4-4cee-93ba-a5be96cb2df7" /></td>
152+
</tr>
153+
</table>
154+
155+
<img width="800" height="470" alt="image" src="https://github.com/user-attachments/assets/fcdae7f6-8bcc-4d0a-bf05-38573cb492ad" />
156+
157+
```console
158+
I (886) main_task: Calling app_main()
159+
[Expressive Eyes Example/I][0.889]: Starting Expressive Eyes Example
160+
[WsS3Touch/I][0.899]: Initializing LCD...
161+
[WsS3Touch/I][0.900]: Initializing SPI...
162+
[WsS3Touch/I][0.906]: Adding device to SPI bus...
163+
[WsS3Touch/I][0.911]: Initializing the display driver...
164+
[WsS3Touch/I][1.321]: Display driver initialized successfully!
165+
W (1322) ledc: the binded timer can't keep alive in sleep
166+
[WsS3Touch/I][1.324]: Initializing display with pixel buffer size: 12000
167+
[WsS3Touch/I][1.334]: Display initialized successfully!
168+
[Expressive Eyes Example/I][1.335]: Display size: 240x280
169+
[Expressive Eyes Example/I][1.342]: Using Monochrome Blue drawer
170+
[Expressive Eyes Example/I][1.392]: Expressive eyes initialized
171+
[Expressive Eyes Example/I][1.392]: Testing different expressions...
172+
[Expressive Eyes Example/I][1.395]: Expression: Neutral
173+
[Expressive Eyes Example/I][11.928]: Expression: Happy
174+
[Expressive Eyes Example/I][22.548]: Expression: Sad
175+
[Expressive Eyes Example/I][33.168]: Expression: Angry
176+
[Expressive Eyes Example/I][43.788]: Expression: Surprised
177+
[Expressive Eyes Example/I][54.407]: Testing look_at functionality
178+
[Expressive Eyes Example/I][54.408]: Looking left
179+
[Expressive Eyes Example/I][59.717]: Looking right
180+
[Expressive Eyes Example/I][65.028]: Looking up
181+
[Expressive Eyes Example/I][70.337]: Looking down
182+
[Expressive Eyes Example/I][75.648]: Looking center
183+
[Expressive Eyes Example/I][80.957]: Starting random demo mode - will run continuously
184+
```
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
idf_component_register(SRC_DIRS "."
2+
INCLUDE_DIRS ".")
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
menu "Expressive Eyes Example Configuration"
2+
3+
choice EXPRESSIVE_EYES_BOARD
4+
prompt "Select Board"
5+
default EXPRESSIVE_EYES_BOARD_ESP_BOX
6+
help
7+
Select the hardware board to run the example on.
8+
9+
config EXPRESSIVE_EYES_BOARD_ESP_BOX
10+
bool "ESP-BOX"
11+
help
12+
Use ESP32-S3-BOX or ESP32-S3-BOX-3 development board.
13+
14+
config EXPRESSIVE_EYES_BOARD_MATOUCH_ROTARY
15+
bool "MaTouch Rotary Display"
16+
help
17+
Use MaTouch Rotary Display board.
18+
19+
config EXPRESSIVE_EYES_BOARD_WS_S3_TOUCH
20+
bool "WS-S3-Touch BSP"
21+
help
22+
Use WS-S3-Touch development board.
23+
24+
endchoice
25+
26+
choice EXPRESSIVE_EYES_DRAWING_METHOD
27+
prompt "Select Drawing Method"
28+
default EXPRESSIVE_EYES_MONOCHROME_BLUE if EXPRESSIVE_EYES_BOARD_WS_S3_TOUCH
29+
default EXPRESSIVE_EYES_FULL_FEATURED
30+
help
31+
Select the eye drawing implementation to use.
32+
33+
config EXPRESSIVE_EYES_FULL_FEATURED
34+
bool "Full Featured (White eyes with black pupils)"
35+
help
36+
Draw realistic eyes with white background, black pupils, eyebrows, and cheeks.
37+
38+
config EXPRESSIVE_EYES_MONOCHROME_BLUE
39+
bool "Monochrome Blue (Electric blue on black)"
40+
help
41+
Draw simple monochrome eyes in electric blue on black background without pupils.
42+
43+
endchoice
44+
45+
endmenu

0 commit comments

Comments
 (0)