PolyMO is een hardware-project waarbij een fysiek wezentje, gebouwd met een ESP32-S3 en een AMOLED-scherm, wordt gekoppeld aan een Android-toestel om doomscrolling te ontmoedigen. Het huisdier reageert direct op de schermtijd van de gebruiker: te veel tijd in sociale media-apps maakt het wezentje ziek, wat uiteindelijk kan leiden tot de dood.
De belangrijkste kenmerken zijn:
- Privacy en On-device AI: Alle verwerking vindt lokaal plaats op de telefoon via tools als
llama.cpp, Whisper en Piper. De app heeft geen internettoestemming, waardoor data het apparaat niet kan verlaten.
- Hardware & Verbinding: Het systeem gebruikt een Waveshare ESP32-S3 Touch AMOLED board dat via Bluetooth Low Energy (BLE) communiceert met de smartphone, die fungeert als de rekenkracht.
- Ontwikkeling: De repository bevat firmware (ESP-IDF), een Android-app en een design-systeem voor het genereren van gezichten en persona's.
- Licenties: Terwijl de broncode onder Apache-2.0 valt, is de uitgegeven APK GPL-3.0 vanwege de integratie van
espeak-ng.
PolyMO: Een fysiek digitaal huisdier dat sterft als je te veel doomscrolt
Wanneer je te lang in een app verblijft die het huisdier "observeert", wordt het ziek. Het blijft ziek totdat je de telefoon weglegt. Ziekte betekent niet direct de dood, maar een ziek huisdier raakt sneller leeg dan een gezond huisdier. Als een huisdier te lang leeg blijft, sterft het definitief, waarna een reset vereist is die je expliciet moet aanvragen. De kern van de ervaring is dat jouw schermtijd de omgeving van het huisdier vormt, in plaats van een instelling binnen de software.
Je communiceert met het wezentje via spraak, waarop het antwoordt via zijn eigen luidspreker. Alles wat het huisdier zegt, wordt lokaal op je telefoon gegenereerd (on-device). Er is geen account en er is geen server.
Privacy en Beveiliging
Het systeem kan niet "naar huis bellen". Dit wordt bewezen door het feit dat de app geen enkele INTERNET-toestemming declareert. De volledige lijst met benodigde permissies is:
BLUETOOTH_CONNECT
BLUETOOTH_SCAN
RECORD_AUDIO
PACKAGEUSAGESTATS
POST_NOTIFICATIONS
RECEIVEBOOTCOMPLETED
FOREGROUND_SERVICE
FOREGROUNDSERVICECONNECTED_DEVICE
Er is een specifieke test die het AndroidManifest.xml uitleest en de build laat falen als er ooit INTERNET wordt toegevoegd. Voor een apparaat dat in je huis luistert en je meldingen kan lezen, is deze mechanische garantie essentieel.
Hoe het werkt
Het huisdier is het object waarmee je interactie hebt; de telefoon fungeert als de rekenkracht die het huisdier leent.
Interactie-stroom:
- ESP32-S3 board: Bevat het AMOLED-gezicht, microfoon, luidspreker, touch-functionaliteit en de simulatie.
- Android telefoon: Bevat Whisper (horen), llama.cpp (denken), Piper (stem) en de schermtijd-sensor.
- Verbinding: Gebeurt via BLE (Bluetooth Low Energy) met Opus-audio en een specifiek protocol.
Wanneer je tegen het huisdier spreekt, streamt het board Opus-audio naar de telefoon. De telefoon transcribeert dit, vraagt een lokaal taalmodel om een antwoord in de stem van het huisdier, synthetiseert de spraak en streamt deze terug naar het huisdier. De telefoon heeft geen gebruikersinterface voor het praten met het huisdier; deze is enkel bedoeld voor de configuratie.
Het huisdier beheert zijn eigen leven. Honger, geluk, levensfase en overlijden worden gesimuleerd op het board, opgeslagen in het eigen flashgeheugen en getrackt door een eigen klok. De telefoon draagt enkel bij via schermtijd, taal en modellen. Als je de telefoon nooit meer verbindt, blijft het huisdier leven, maar wordt het stil.
Hardware
- Board: Waveshare ESP32-S3 Touch AMOLED 1.8
- Display: 1.8-inch 368×448 AMOLED, capacitieve touch
- Oriëntatie: De UI draait geroteerd (448 breed, 368 hoog)
- Audio: Ingebouwde microfoon en luidspreker
- Verbinding: BLE naar een Android-telefoon
Zowel revisie V1 als V2 van het board worden ondersteund; de panel-driver (SH8601 of CO5300) wordt tijdens runtime gedetecteerd.
Documentatie
Het project bevat twee centrale documenten waarin beslissingen per sectienummer worden geciteerd:
- DESIGN.md: Bevat product- en UX-beslissingen. Hierin staan het state-model, de flows en de argumentatie. Voorbeelden zijn: waarom de schermtijd-toelating per sessie gaat in plaats van per dag, en waarom de score "verzadiging" (satiety) wordt genoemd in plaats van "honger" (om logische leesbaarheid in de code te garanderen).
- CLAUDE.md: Instructies voor het werken aan het project (geschreven voor Claude Code). Dit dient als conventiebestand met build-commando's, bekende valkuilen en de regel dat gezichten en persona's gegenereerd worden en niet handmatig bewerkt mogen worden.
Structuur van de Repository
pet-esp32/: ESP-IDF firmware (display, microfoon, luidspreker en simulatie).
android/: De app (BLE, Whisper, llama.cpp, Piper, schermtijd-tracking).
design-system/: Design tokens, gezichten en persona's (de 'source of truth').
tools/: Generatoren die gezichten en persona's omzetten in firmware- en app-code.
shared/: De wire-protocol header die door beide zijden wordt gedeeld.
hardware/: Printbare behuizingen (STL).
licences/: Volledige teksten voor meegeleverde lettertypen en GPL-3.0.
DESIGN.md: Product- en UX-beslissingen.
CLAUDE.md: Build-commando's en conventies.
Let op: De firmware en de app delen een protocol. Ze moeten synchroon worden gewijzigd. Het is aanbevolen om beide te flashen vanaf dezelfde commit om incompatibiliteit te voorkomen.
Bouwen (Building)
Firmware
. ~/esp/esp-idf/export.sh
cd pet-esp32
idf.py build
idf.py -p /dev/cu.usbmodem* flash
Let op: Het display kan na het flashen zwart blijven tot het board opnieuw is opgestart (USB-kabel trekken en opnieuw aansluiten).
Android app
De build vereist JDK 21. Een nieuwere JDK (zoals 25) zal leiden tot fouten zonder duidelijke oorzaak. Daarnaast is de Android SDK vereist via ANDROID_HOME of een sdk.dir regel in android/local.properties.
cd android
export ANDROID_HOME="$HOME/Library/Android/sdk"
JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home" \
./gradlew assembleDebug
Native dependencies
De app linkt naar llama.cpp, whisper.cpp, Piper, Opus en espeak-ng. Deze bevinden zich niet in de repository (circa 1.3 GB aan third-party source). De exacte commits zijn vastgelegd in NOTICE. Gebruik het volgende script om bronnen op te halen:
tools/fetch-natives.sh
Twee prebuilt shared libraries moeten handmatig worden geplaatst.
Tests
Er zijn 512 tests die geen apparaat vereisen:
cd android && ./gradlew testDebugUnitTest
Deze testen logica, WCAG-contrastverhoudingen, het verbod op raw .dp/.sp literals in UI-code, en de synchronisatie van gegenereerde assets.
Modellen
De app wordt zonder modellen geleverd. Je dient er drie zelf te importeren via de systeem-filepicker:
| Rol | Formaat | Notitie |
| Denken | .gguf | Elk klein instruct-model dat llama.cpp kan laden |
| Horen | .bin | Een Whisper-model |
| Stem | .onnx | Een Piper-stem |
Generatie van Gezichten en Stemmen
De bronnen voor de gezichten en persona's bevinden zich in design-system/faces/.json en design-system/personas/.json. De firmware-tabellen, app-sets, notificatie-iconen en persona-prompts worden gegenereerd via:
tools/gen-faces.py
tools/gen-personas.py
Er zijn strikte designregels ingebouwd: een blij gezicht moet glimlachen, een dood gezicht heeft geen mond, en een persona mag geen vragen stellen of lijsten met apps hardop voorlezen.
Licenties
PolyMO maakt gebruik van drie licentielagen:
| Onderdeel | Licentie | Opmerking |
pet-esp32/ firmware | Apache-2.0 | Schoon, linkt naar niets copyleft |
android/ source, design-system/, tools/ | Apache-2.0 | Herbruikbaar onder Apache-voorwaarden |
| Uitgegeven APK | GPL-3.0 | Linkt naar espeak-ng, waardoor het binary GPL erft |
Waarom de APK verschilt: De native library van de app linkt naar espeak-ng (GPL-3.0-or-later) voor het omzetten van tekst naar fonemen. Omdat Apache-2.0 eenrichtingscompatibel is met GPL, blijft de broncode Apache-2.0, maar moet elk binary dat espeak-ng linkt, worden gedistribueerd onder GPL-3.0. De firmware is hiervan niet betrokken, omdat deze enkel reeds gesynthetiseerde audio via BLE ontvangt.
PolyMO: Een fysiek digitaal huisdier dat sterft als je te veel doomscrolt
Wanneer je te lang in een app verblijft die het huisdier "observeert", wordt het ziek. Het blijft ziek totdat je de telefoon weglegt. Ziekte betekent niet direct de dood, maar een ziek huisdier raakt sneller leeg dan een gezond huisdier. Als een huisdier te lang leeg blijft, sterft het definitief, waarna een reset vereist is die je expliciet moet aanvragen. De kern van de ervaring is dat jouw schermtijd de omgeving van het huisdier vormt, in plaats van een instelling binnen de software.
Je communiceert met het wezentje via spraak, waarop het antwoordt via zijn eigen luidspreker. Alles wat het huisdier zegt, wordt lokaal op je telefoon gegenereerd (on-device). Er is geen account en er is geen server.
Privacy en Beveiliging
Het systeem kan niet "naar huis bellen". Dit wordt bewezen door het feit dat de app geen enkele INTERNET-toestemming declareert. De volledige lijst met benodigde permissies is:
BLUETOOTH_CONNECT
BLUETOOTH_SCAN
RECORD_AUDIO
PACKAGEUSAGESTATS
POST_NOTIFICATIONS
RECEIVEBOOTCOMPLETED
FOREGROUND_SERVICE
FOREGROUNDSERVICECONNECTED_DEVICE
Er is een specifieke test die het AndroidManifest.xml uitleest en de build laat falen als er ooit INTERNET wordt toegevoegd. Voor een apparaat dat in je huis luistert en je meldingen kan lezen, is deze mechanische garantie essentieel.
Hoe het werkt
Het huisdier is het object waarmee je interactie hebt; de telefoon fungeert als de rekenkracht die het huisdier leent.
Interactie-stroom:
- ESP32-S3 board: Bevat het AMOLED-gezicht, microfoon, luidspreker, touch-functionaliteit en de simulatie.
- Android telefoon: Bevat Whisper (horen), llama.cpp (denken), Piper (stem) en de schermtijd-sensor.
- Verbinding: Gebeurt via BLE (Bluetooth Low Energy) met Opus-audio en een specifiek protocol.
Wanneer je tegen het huisdier spreekt, streamt het board Opus-audio naar de telefoon. De telefoon transcribeert dit, vraagt een lokaal taalmodel om een antwoord in de stem van het huisdier, synthetiseert de spraak en streamt deze terug naar het huisdier. De telefoon heeft geen gebruikersinterface voor het praten met het huisdier; deze is enkel bedoeld voor de configuratie.
Het huisdier beheert zijn eigen leven. Honger, geluk, levensfase en overlijden worden gesimuleerd op het board, opgeslagen in het eigen flashgeheugen en getrackt door een eigen klok. De telefoon draagt enkel bij via schermtijd, taal en modellen. Als je de telefoon nooit meer verbindt, blijft het huisdier leven, maar wordt het stil.
Hardware
- Board: Waveshare ESP32-S3 Touch AMOLED 1.8
- Display: 1.8-inch 368×448 AMOLED, capacitieve touch
- Oriëntatie: De UI draait geroteerd (448 breed, 368 hoog)
- Audio: Ingebouwde microfoon en luidspreker
- Verbinding: BLE naar een Android-telefoon
Zowel revisie V1 als V2 van het board worden ondersteund; de panel-driver (SH8601 of CO5300) wordt tijdens runtime gedetecteerd.
Documentatie
Het project bevat twee centrale documenten waarin beslissingen per sectienummer worden geciteerd:
- DESIGN.md: Bevat product- en UX-beslissingen. Hierin staan het state-model, de flows en de argumentatie. Voorbeelden zijn: waarom de schermtijd-toelating per sessie gaat in plaats van per dag, en waarom de score "verzadiging" (satiety) wordt genoemd in plaats van "honger" (om logische leesbaarheid in de code te garanderen).
- CLAUDE.md: Instructies voor het werken aan het project (geschreven voor Claude Code). Dit dient als conventiebestand met build-commando's, bekende valkuilen en de regel dat gezichten en persona's gegenereerd worden en niet handmatig bewerkt mogen worden.
Structuur van de Repository
pet-esp32/: ESP-IDF firmware (display, microfoon, luidspreker en simulatie).
android/: De app (BLE, Whisper, llama.cpp, Piper, schermtijd-tracking).
design-system/: Design tokens, gezichten en persona's (de 'source of truth').
tools/: Generatoren die gezichten en persona's omzetten in firmware- en app-code.
shared/: De wire-protocol header die door beide zijden wordt gedeeld.
hardware/: Printbare behuizingen (STL).
licences/: Volledige teksten voor meegeleverde lettertypen en GPL-3.0.
DESIGN.md: Product- en UX-beslissingen.
CLAUDE.md: Build-commando's en conventies.
Let op: De firmware en de app delen een protocol. Ze moeten synchroon worden gewijzigd. Het is aanbevolen om beide te flashen vanaf dezelfde commit om incompatibiliteit te voorkomen.
Bouwen (Building)
Firmware
. ~/esp/esp-idf/export.sh
cd pet-esp32
idf.py build
idf.py -p /dev/cu.usbmodem* flash
Let op: Het display kan na het flashen zwart blijven tot het board opnieuw is opgestart (USB-kabel trekken en opnieuw aansluiten).
Android app
De build vereist JDK 21. Een nieuwere JDK (zoals 25) zal leiden tot fouten zonder duidelijke oorzaak. Daarnaast is de Android SDK vereist via ANDROID_HOME of een sdk.dir regel in android/local.properties.
cd android
export ANDROID_HOME="$HOME/Library/Android/sdk"
JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home" \
./gradlew assembleDebug
Native dependencies
De app linkt naar llama.cpp, whisper.cpp, Piper, Opus en espeak-ng. Deze bevinden zich niet in de repository (circa 1.3 GB aan third-party source). De exacte commits zijn vastgelegd in NOTICE. Gebruik het volgende script om bronnen op te halen:
tools/fetch-natives.sh
Twee prebuilt shared libraries moeten handmatig worden geplaatst.
Tests
Er zijn 512 tests die geen apparaat vereisen:
cd android && ./gradlew testDebugUnitTest
Deze testen logica, WCAG-contrastverhoudingen, het verbod op raw .dp/.sp literals in UI-code, en de synchronisatie van gegenereerde assets.
Modellen
De app wordt zonder modellen geleverd. Je dient er drie zelf te importeren via de systeem-filepicker:
| Rol | Formaat | Notitie |
| Denken | .gguf | Elk klein instruct-model dat llama.cpp kan laden |
| Horen | .bin | Een Whisper-model |
| Stem | .onnx | Een Piper-stem |
Generatie van Gezichten en Stemmen
De bronnen voor de gezichten en persona's bevinden zich in design-system/faces/.json en design-system/personas/.json. De firmware-tabellen, app-sets, notificatie-iconen en persona-prompts worden gegenereerd via:
tools/gen-faces.py
tools/gen-personas.py
Er zijn strikte designregels ingebouwd: een blij gezicht moet glimlachen, een dood gezicht heeft geen mond, en een persona mag geen vragen stellen of lijsten met apps hardop voorlezen.
Licenties
PolyMO maakt gebruik van drie licentielagen:
| Onderdeel | Licentie | Opmerking |
pet-esp32/ firmware | Apache-2.0 | Schoon, linkt naar niets copyleft |
android/ source, design-system/, tools/ | Apache-2.0 | Herbruikbaar onder Apache-voorwaarden |
| Uitgegeven APK | GPL-3.0 | Linkt naar espeak-ng, waardoor het binary GPL erft |
Waarom de APK verschilt: De native library van de app linkt naar espeak-ng (GPL-3.0-or-later) voor het omzetten van tekst naar fonemen. Omdat Apache-2.0 eenrichtingscompatibel is met GPL, blijft de broncode Apache-2.0, maar moet elk binary dat espeak-ng linkt, worden gedistribueerd onder GPL-3.0. De firmware is hiervan niet betrokken, omdat deze enkel reeds gesynthetiseerde audio via BLE ontvangt.