Air Dry Clay Ghost Haunted House Pomodoro

by jwang1027 in Circuits > Arduino

286 Views, 6 Favorites, 0 Comments

Air Dry Clay Ghost Haunted House Pomodoro

IMG_1048.PNG
查看最近的照片.png
截屏2025-12-07 18.27.55.png

Video: https://youtu.be/teC6-oVyTb0

I have always wanted to try making my own dollhouse and integrate it with some practical functionality. That's why I designed and created this Haunted-House Pomodoro. I hope it can serve as a desktop ornament to help users develop good study and work habits, becoming a regular part of their daily life with fun.

The inspiration comes from my recent design of a little ghost font and Christmas gingerbread house.

The idea is to divide different time blocks into different-sized little ghosts. When you press the first ghost to start, it begins to flicker.

The first 25-minute ghost slowly brightens like a breathing light. When the 25-minute work session ends, that ghost stays lit.

Then the next 5-minute break ghost starts flickering. This cycle repeats four times.

After that, all the ghosts light up. Users can extend the break if they want, or start a new Pomodoro round.

Ideally, users can swap out the default small ghosts for different sizes—for example, a large 60 minute ghost, which works better for design students.

Supplies

截屏2025-12-07 18.29.11.png
截屏2025-12-07 18.30.29.png
截屏2025-12-07 19.08.09.png
截屏2025-12-07 20.44.19.png

Lightweight air-dry clay with Sculpting tools (white model magic small pack x2)

Acrylic paints and black marker or fine-tip pen

Acrylic board base

Cardboard

Foam board

Hot glue

Arduino Nano ESP32 x1

Breadboard x1

Switch x1

LED light bulbs x8

Power cord x1

Wires x20

Heat shrink tubing x8

截屏2025-12-07 19.03.00.png
截屏2025-12-07 19.02.23.png
截屏2025-12-07 19.04.26.png

Determine the size of each ghost based on the size of your LEDs.

The ghosts representing longer time periods can be slightly larger than those representing shorter ones. My technique is to first roll nine spheres, flatten them, and then place them over a finger or a thick pen barrel to create the hollow, ghostly shape.

Then, use your finger to slowly press in circles until the clay is evenly distributed and looks smooth.

Next, use clay to create some accessories, such as a computer (for work), a drinking cup, snack foods, and so on.

Once the clay is completely dry, you can use a fine-tip pen or thin marker to draw on expressions, and use acrylic paints to color the accessories.

截屏2025-12-07 19.05.10.png
截屏2025-12-07 19.05.40.png

Arrange the finished ghosts on an easy-to-cut board to determine the room dimensions.

Then, you can cut the base and the two walls and cover them with clay for the surface.

Once the clay is completely dry, you can use acrylics to paint the walls.

When assembling the floor and walls, you can use clay strips to reinforce and cover the joints. If you include a window, you can add a window frame.



截屏2025-12-07 19.07.24.png
截屏2025-12-07 19.06.36.png
截屏2025-12-07 19.07.01.png

Use clay to create decorative hanging pictures and a fireplace.

Once the clay is dry, you can use a fine-tip pen to draw patterns on it.

Arrange the pictures on the wall to determine the layout and composition first.

Once the position is confirmed, use hot glue to secure them.

截屏2025-12-07 19.44.16.png

Place the ghosts in the room to determine the required position for each LED light.

Use a nail, a drill, or any convenient tool to make the holes.

You can use disposable chopsticks to expand the space.

Insert the LED bulbs and the switch, and confirm the position and sequence again.



截屏2025-12-07 19.48.44.png
截屏2025-12-07 19.45.38.png
截屏2025-12-07_20.35.17.png

Solder the Arduino Nano ESP32 and the breadboard.

Test and solder the LED bulbs and the extension wires.

Use different colors to distinguish which wire connects to the negative and which connects to the positive terminal.

Use heat-shrink tubing to support the LED bulbs so that the clay ghosts can be lifted slightly, creating a floating effect.

Solder the switch and LED bulbs onto the breadboard.

You can connect all the ground wires first, and then connect each bulb to each pin port. Mark the order of the bulbs and the corresponding pin numbers.


查看最近的照片 2.png

Connect the Arduino Nano ESP32 to the computer using a data cable.

Use the Arduino to test whether all the bulbs light up.

After confirming that all bulbs are free of soldering issues, you can upload the Pomodoro code into the Arduino.

Place the small ghosts onto the bulbs sequentially.

After all tests pass, secure the breadboard to the exterior wall or underneath the floor.

Completed.

Test code:

// 定义引脚
const int BUTTON_PIN = 13; // 开关接口 D13

// 注意:引脚 10, 8, 6, 4, 2, 9, 7, 3
const int LED_PINS[8] = {
10, // LED1
8, // LED2
6, // LED3
4, // LED4
2, // LED5
9, // LED6
7, // LED7
3 // LED8
};
const int NUM_LEDS = 8;

void setup() {
Serial.begin(115200);
Serial.println("LED and Button Test Initialized.");


pinMode(BUTTON_PIN, INPUT_PULLUP);

// 设置 LED 引脚为输出
for (int i = 0; i < NUM_LEDS; i++) {
pinMode(LED_PINS[i], OUTPUT);
digitalWrite(LED_PINS[i], LOW); // 初始全部熄灭
}
}

void loop() {
// 读取开关状态。由于使用了 INPUT_PULLUP,按下时是 LOW
int buttonState = digitalRead(BUTTON_PIN);

if (buttonState == LOW) {
// 开关被按下:所有灯常亮
Serial.println("Button Pressed - All LEDs ON");
for (int i = 0; i < NUM_LEDS; i++) {
digitalWrite(LED_PINS[i], HIGH);
}

delay(50);
} else {
// 开关松开:所有灯熄灭
// 注意:如果是瞬时开关,松开时会是 HIGH
for (int i = 0; i < NUM_LEDS; i++) {
digitalWrite(LED_PINS[i], LOW);
}

}
}

Pomodoro code:

// Ghost House Pomodoro - 8 LEDs with restart anytime, NO PWM
// Board: Arduino Nano ESP32

const int BUTTON_PIN = 13; // 开关 D13

const int LED_PINS[8] = {
10, // LED1
8, // LED2
6, // LED3
4, // LED4
2, // LED5
9, // LED6
7, // LED7
3 // LED8
};

// 一个“呼吸循环”总时长(ms)
const unsigned long BREATHE_CYCLE_MS = 5000;
// 其中 4.5 秒亮、0.5 秒灭
const unsigned long ON_TIME_MS = 4500;
const unsigned long OFF_TIME_MS = 500;

// 每个灯要呼吸几次(1 次=5 秒)
const int BREATH_COUNT[8] = {
300, // LED1: 25min
60, // LED2: 5min
300, // LED3: 25min
60, // LED4: 5min
300, // LED5: 25min
60, // LED6: 5min
300, // LED7: 25min
60 // LED8: 5min
};

// ------------ 工具函数 ------------

void setLedBrightness(int pin, int b) {
if (b <= 0) {
digitalWrite(pin, LOW);
} else {
digitalWrite(pin, HIGH);
}
}

void allOff() {
for (int i = 0; i < 8; i++) {
setLedBrightness(LED_PINS[i], 0);
}
}

bool checkRestart() {
if (digitalRead(BUTTON_PIN) == LOW) { // INPUT_PULLUP: LOW = 被按下
delay(30); // 消抖
if (digitalRead(BUTTON_PIN) == LOW) {
// 等松手
while (digitalRead(BUTTON_PIN) == LOW) {
delay(10);
}
return true;
}
}
return false;
}

// ------------ 一次“呼吸循环”:亮 4.5s,灭 0.5s ------------
// 中途如果按下按钮,就返回 true 表示要重启
bool breatheOnce(int pin) {
unsigned long start;

// 亮 4.5 秒
setLedBrightness(pin, 255); // 亮
start = millis();
while (millis() - start < ON_TIME_MS) {
if (checkRestart()) return true;
delay(20); // 分段检查按键
}

// 灭 0.5 秒
setLedBrightness(pin, 0); // 灭
start = millis();
while (millis() - start < OFF_TIME_MS) {
if (checkRestart()) return true;
delay(20);
}

return false; // 正常完成一个循环
}

// 某个灯呼吸 N 次,然后常亮
// 中途按键就返回 true(重启)
bool breatheCyclesThenHold(int pin, int cycles) {
setLedBrightness(pin, 0); // 确保从灭开始

for (int c = 0; c < cycles; c++) {
if (breatheOnce(pin)) {
return true; // 请求重启
}
}

// 呼吸结束,保持常亮
setLedBrightness(pin, 255);
// 刚亮起来的时候也检查一次
if (checkRestart()) return true;

return false;
}

// ------------ 整个 8 灯流程 ------------
// 返回 true = 中途被打断重启;false = 正常跑完
bool runFullSequence() {
allOff();

for (int i = 0; i < 8; i++) {
int pin = LED_PINS[i];
int cycles = BREATH_COUNT[i];

if (breatheCyclesThenHold(pin, cycles)) {
return true; // 中途按键,要重头来
}
}

// 走到这里说明 8 个灯都已经常亮了
return false;
}

void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP); // 按键一边接 D13,一边接 GND

for (int i = 0; i < 8; i++) {
pinMode(LED_PINS[i], OUTPUT);
}

allOff();
}

void loop() {
// 等待按下开关开始一轮
if (checkRestart()) {
while (true) {
bool interrupted = runFullSequence();
if (!interrupted) {
// 一轮正常结束:8 灯常亮,跳出循环回到等待状态
break;
}
// 如果中途被打断(interrupted == true)
// while 会继续,再次 runFullSequence()
// 等于从灯1重新开始
}
}

// 等下一次按键
}