12 Commits

Author SHA1 Message Date
Branko May Trinkwald
3d90710bc1 Auto-load waldwaechter.sh im Mission Selector
Jetzt werden alle Crew-Befehle automatisch verfügbar wenn
der Mission Selector gestartet wird:

 crew_tokens
 crew_doctor
 crew_syntax
 crew_status
 crew_memory
 crew_help

Plus alle 17 Waldwächter-Funktionen!

User Experience:
./crumb-mission-selector.sh → Crew-Befehle sofort verfügbar! 💚

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 20:16:06 +01:00
Branko May Trinkwald
e96d6cc99e 🐚 Fix: zsh indirekte Variable in crew_doctor
Problem: 'bad substitution' bei crew_doctor
→ ${!var} funktioniert nur in bash, nicht in zsh

Lösung:
- if BASH_VERSION → ${!loaded_check_var}
- elif ZSH_VERSION → ${(P)loaded_check_var}

Jetzt funktioniert crew_doctor in beiden Shells! 

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 20:03:33 +01:00
Branko May Trinkwald
6fefaf9081 🐚 Fix: zsh Pfad-Berechnung mit ${(%):-%x}
KRITISCHER FIX: BASH_SOURCE[0] funktioniert nicht in zsh!

Problem:
- BASH_SOURCE[0] ist bash-spezifisch
- In zsh war SCRIPT_DIR leer → WALDWAECHTER_DIR falsch
- CRUMB_LOGS_DIR: /Users/bmt/Documents/logs (falsch!)
- Sollte: /Users/bmt/Documents/CF_Zero_V1/logs

Lösung:
- if BASH_VERSION → BASH_SOURCE[0]
- elif ZSH_VERSION → ${(%):-%x}
- else → fallback $0

Jetzt funktionieren Pfade in beiden Shells korrekt!

crew_doctor wird jetzt den richtigen Pfad zeigen 

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 19:54:13 +01:00
Branko May Trinkwald
43a16d30f2 🐚 Fix: zsh Kompatibilität für crew_doctor & crew_syntax
Problem: export -f funktioniert nicht in zsh, nur in bash
→ crew_doctor und crew_syntax wurden nicht geladen in zsh

Lösung:
- Prüfe BASH_VERSION
- export -f nur in bash
- In zsh sind Funktionen automatisch verfügbar

Jetzt funktioniert waldwaechter.sh in beiden Shells:
 bash (export -f wird verwendet)
 zsh (Funktionen direkt verfügbar)

macOS Standard ist zsh → kritischer Fix!

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 19:51:24 +01:00
Branko May Trinkwald
7151749826 🩺 New: crew_doctor & crew_syntax - OZMAI würde nicken
"Systeme die sich selbst überprüfen" - Selbstdiagnose implementiert!

 crew_doctor - System-Diagnose:
  📋 waldwaechter.sh Version Check (erkennt veraltete Versionen!)
  📂 CRUMB_LOGS_DIR Pfad-Validierung
  🌲 Alle 17 Waldwächter Scripts vorhanden?
  🔧 Dependencies Check (jq, bc, curl)
  📊 Token-Logging in allen Scripts?
  🔑 API Key konfiguriert?

  → Warnt wenn "source lib/waldwaechter.sh" nötig ist!
  → Löst das Problem von vorhin automatisch

 crew_syntax - Syntax Check:
  🔍 bash -n für alle Scripts
  📝 lib/waldwaechter.sh + 17 Character Scripts
  📋 Alle Mission Scripts
  📊 Detaillierte Fehler-Ausgabe bei Problemen

🔧 Technische Details:
- Version-Marker via mtime (modification time)
- Export WALDWAECHTER_LOADED_${mtime}=1
- crew_doctor erkennt ob Version aktuell ist
- LC-independent (stat -f macOS, stat -c Linux)

🔍 OZMAI-Prinzip: "Ich schau drauf, nicht drüber hinweg"
→ Präventive Diagnose statt reaktive Fehlersuche

Neue Befehle in crew_help dokumentiert.

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 19:38:35 +01:00
Branko May Trinkwald
0700ec0a41 🔧 Fix: Locale-Problem in crew_tokens behoben
Problem: Deutsche Locale (Komma als Dezimaltrenner) vs.
JSON/bc output (Punkt als Dezimaltrenner) → printf Fehler

 Lösung:
- LC_NUMERIC=C für gesamte crew_tokens Funktion
- Konsistente Zahlenformatierung (Punkt als Dezimaltrenner)
- Keine printf "invalid number" Fehler mehr

📊 Ergebnis:
- Alle 12 aktiven Waldwächter korrekt angezeigt
- Token-Zahlen akkurat: 20021 Tokens total
- Kosten transparent: ~$0.017558
- "Was kostet die Frage eines Kindes?" → Jetzt mit Antwort! ✓

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 19:31:35 +01:00
Branko May Trinkwald
43171dd884 🐛 Fix: Crew-Befehle implementiert (crew_tokens, crew_status, crew_memory, crew_help)
Bug gefunden: Schnecki zeigte 671 Tokens, aber crew_tokens zeigte 0.
Grund: Die 4 Crew-Befehle existierten noch nicht!

 Implementiert:

1. **crew_tokens** - Token-Tracking funktioniert jetzt!
   - Liest alle logs/*/token_log.json
   - Summiert total_tokens und cost
   - Zeigt Pro-Character und Gesamt-Übersicht
   - "Was kostet die Frage eines Kindes?" ✓

2. **crew_status** - Status aller 17 Waldwächter
   - Zeigt welche Waldwächter genutzt wurden
   - Wann zuletzt verwendet
   -  aktiv /  noch nicht genutzt

3. **crew_memory** - Log-basierte Suche
   - Durchsucht alle history.json Dateien
   - crew_memory "LED" findet alle Erwähnungen
   - Ehrlich: "Log-basiertes Gedächtnis"

4. **crew_help** - Übersicht aller Befehle
   - Alle 17 Waldwächter aufgelistet
   - Nach Teams gruppiert
   - Beispiele enthalten

📊 Token-Transparenz jetzt funktionsfähig!
OZMAI würde nicken. 🔍

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 19:26:00 +01:00
Branko May Trinkwald
819d2d4ec0 ⚙️ OZMAI Präzisierungen: Ehrlichkeit über Marketing
OZMAI hat zentrale Inkonsistenzen identifiziert und korrigiert.

 5 Haupt-Korrekturen:

1. **17 Waldwächter** (nicht 15)
   - 17 Character Scripts existieren tatsächlich
   - Alle Vorkommen korrigiert (README + KEKSHANDBUCH)

2. **Crew Memory präzisiert**
   - "Log-basiertes Gedächtnis (dateibasiert, nachvollziehbar)"
   - NICHT "autonomes Agentensystem"
   - Zero-Trust-kompatibel

3. **LiPo Safety Disclaimer**
   - ⚠️ Lern- und Simulationskonzept
   - Echte LiPo-Akkus nur unter Aufsicht
   - Haftungsschutz

4. **Token-Kosten als Richtwerte**
   - "Richtwerte, modellabhängig"
   - Transparenz statt Abrechnung
   - Passt zur Kinderfrage-Philosophie

5. **Hardware-Anforderungen realistisch**
   - Grundsystem: Pi Zero kompatibel
   - Vision/ML: Pi 4+ oder Desktop
   - Bash 3.2 → Bash 4+ empfohlen

🔺 **Das Dreieck präzisiert:**
   - "Didaktisches Modell, nicht technisches Modul"
   - Struktur, Flow, Balance

📝 **Weitere Anpassungen:**
   - Bash 3.2 Kompatibilität klargestellt
   - OpenCV Hardware-Anforderungen transparent
   - Mond Maschine: Pi 4+ empfohlen

"Präzision statt Marketing" - OZMAI schaut drauf! 🔍

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 18:47:11 +01:00
Branko May Trinkwald
7679805390 🌱 Crumb Codex: "Machen statt Lernen"
Alle Vorkommen von "pädagogisch" durch den Crumb Codex ersetzt:

 Philosophie-Update:
- "nur die frage stärkt den krümel & wurzel"
- "machen statt lernen"

📝 Änderungen:
- README.md: "Crumb Codex: Fragen stärken Krümel & Wurzel"
- README.md: "Machen statt Lernen - Fragen stärken die Wurzel"
- .env.template: "TOKEN BUDGET (Crumb Codex: Machen statt Lernen)"
- KEKSHANDBUCH: "interaktives Bash-System zum Machen & Fragen"
- KEKSHANDBUCH: "Der Crumb Codex: Machen statt Lernen"

Von Belehrung zu Befähigung! 💚

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 18:25:48 +01:00
Branko May Trinkwald
f85b4d48d9 📖 README komplett aktualisiert - v0.1-robots-complete
 Neue Inhalte:
- 🤖 Komplette Robots-Kategorie (3 Missionen beschrieben)
- 🌙 Mond Maschine prominent platziert
- 🌲 Alle 15 Waldwächter nach Teams organisiert
- 📊 Token-Tracking & Kosten transparent
- 🌍 Alle Philosophien dokumentiert
- 🏗️ Projekt-Struktur aktualisiert
- 🔗 Links zu Simulatoren & Demos

Von 52 auf 267 Zeilen gewachsen! 💚

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 17:23:11 +01:00
Branko May Trinkwald
3ee5214405 🌙🌈 Mond Maschine - Rainbow Predictor Mission!
"Vorhersagen heißt verstehen - Die Natur durch Code begreifen"

**Eine neue Computer Vision Mission!**

Inspired by: "Eine Mond Maschine die mir zeigt wann ich
regenbogen zählen kann?" 💚

**Was die Mond Maschine kann:**
- 🌙 Mond-Phasen tracken & berechnen
- 🌦️ Wetter-Daten analysieren (APIs)
- 📸 Computer Vision: Regenbogen detektieren (OpenCV)
- 🔮 Vorhersage-Algorithmus (ML Light)
- 🌈 Mondregenbogen! (Lunar Rainbow bei Vollmond)

**8 Phasen:**
1. Vision - Maya-Eule über Vorhersage vs Beobachtung
2. Das Dreieck - Daten-Struktur, Flow & Balance
3. Hardware - Kamera-Setup (Webcam/RasPi Cam)
4. Computer Vision - OpenCV & HSV-Farbraum
5. Daten-Integration - Wetter-API & Mond-Berechnung
6. Vorhersage-Algorithmus - Feature Engineering & Scoring
7. Visualisierung - ASCII Mond-Phasen & Dashboard
8. Mondregenbogen - Die magische Legende

**Alle 13 Waldwächter:**
- 🔺 Dreieck: DumboSQL, FunkFox, Taichi Taube
- 🔧 Hardware: CapaciTobi, Schnecki, Schraubbär
- 💻 Code: SnakePy (OpenCV!), PepperPHP, Spider
- 🔐 System: CrabbyRust, Vektor
- 🎨 Art: ASCII-Monster
- 🦉 Wisdom: Maya-Eule

**Learning Areas:**
- Computer Vision & OpenCV
- Image Processing (HSV color space)
- Weather API integration
- Astronomical calculations (moon phases)
- Machine Learning concepts
- Prediction algorithms
- Data visualization

**Hardware:**
- Kamera (USB Webcam / Raspberry Pi Camera)
- Optional: Wetterfestes Gehäuse für Outdoor
- Python + OpenCV + ephem

**Next Steps:**
pip install opencv-python numpy requests ephem

Die dritte Robot-Mission ist bereit! 🌙
Von Krümels Vision zur Mond Maschine! 💚

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 16:55:16 +01:00
Branko May Trinkwald
39011a555f 🧹 Großes Aufräumen - Repo schlank gemacht!
**Gelöscht:**

📁 17 alte Log-Directories:
- ./.tobi_logs, ./.eule_logs, ./.funkfox_logs
- ./.schraubaer_logs, ./.schnecki_logs, ./.deepbit_logs
- ./.bugsy_logs, ./.schnippsi_logs, ./.templatus_logs
- ./.snake_logs, ./.taube_logs, ./.bits_logs
- ./.dumbo_logs, ./.pepper_logs, ./.stage_logs
- ./.missionstage_log, ./.bugsy_log
→ Jetzt: logs/{character}/ statt versteckt!

📁 7 Config/Cache Directories:
- ./.config, ./.local, ./.cache, ./.dotnet
- ./.crumbair, ./.claude, ./.pp_backup
→ Gehören nicht ins Repo!

📦 Alte Backups & Temp Files:
- bits_logs/ (leer)
- crumbforest_roles_v2/ (alter Backup)
- crumbforest_zero_backup_*.zip (2 Backups)
- snake_camera_vision/ & _v2/ (alte Python Apps)
- snake_camera_vision.zip
- mission_deepbit_dns_*.log (3 alte Logs)
- vegeta_disk.sh.save, backup_zero.sh
- fix_token_logs.sh (nicht mehr nötig)

**Behalten:**
 logs/ (neue Struktur!)
 crumbforest_roles/, missions/, lib/
 crumb-mission-selector.sh
 CLAUDE.md, README.md, KEKSHANDBUCH

**Ergebnis:** Repo ist jetzt viel übersichtlicher! 🌲

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 16:34:44 +01:00
33 changed files with 1153 additions and 1218 deletions

View File

@@ -36,7 +36,7 @@ QDRANT_URL="http://localhost:6333"
QDRANT_COLLECTION="crumbforest_memory"
QDRANT_API_KEY="" # Optional, meist leer bei local
# === TOKEN BUDGET (Pädagogisch) ===
# === TOKEN BUDGET (Crumb Codex: Machen statt Lernen) ===
# Tages-Budget für bewusstes Fragen (in Tokens)
# 0 = unbegrenzt, >0 = Limit (z.B. 10000 = ~20 Fragen)

View File

@@ -6,12 +6,12 @@
🌲 CRUMBFOREST 🌲
"Wo Fragen wachsen"
Die 15 Waldwächter sind bereit!
Die 17 Waldwächter sind bereit!
```
## 📖 Was ist das hier?
Crumbforest ist ein **pädagogisches Bash-Lernsystem** mit 15 KI-Charakteren (Waldwächter), die Kindern durch Metaphern, Poesie und Geduld das Programmieren beibringen.
Crumbforest ist ein **interaktives Bash-System zum Machen & Fragen** mit 17 KI-Charakteren (Waldwächter), die Krümeln durch Metaphern, Poesie und Geduld das Programmieren zeigen.
**Philosophie:** *"Was kostet die Frage eines Kindes?"*
Im Wald unbezahlbar - aber Token lehren achtsames Fragen.
@@ -61,11 +61,12 @@ crew_tokens
---
## 🌲 Die 15 Waldwächter
## 🌲 Die 17 Waldwächter
### 🔺 Das Dreieck (Foundation)
**Ohne dieses Dreieck geht es nicht!**
*Das Dreieck ist ein didaktisches Modell (Struktur, Flow, Balance), kein technisches Modul.*
| Charakter | Rolle | Spezialität |
|-----------|-------|-------------|
@@ -169,7 +170,7 @@ In der CrumbCrew-Shell verfügbar:
| Befehl | Beschreibung |
|--------|--------------|
| `crew_help` | Diese Hilfe anzeigen |
| `crew_status` | Status aller 15 Waldwächter |
| `crew_status` | Status aller 17 Waldwächter |
| `crew_tokens` | Token-Verbrauch ALLER Charaktere |
| `crew_memory` | Erinnerungen durchsuchen |
@@ -365,7 +366,7 @@ echo $OPENROUTER_API_KEY
Schau dir `crumbforest_roles/funkfox_zero.sh` als Template an:
1. Load .env
2. Crew Memory Functions
2. Crew Memory Functions (log-basiert, dateibasiert, nachvollziehbar)
3. System Prompt mit Persönlichkeit
4. OpenRouter API Call
5. Token Tracking
@@ -378,8 +379,8 @@ Neue Kategorien in `crumb-mission-selector.sh` hinzufügen.
## 🎯 Credits
**Die 15 Waldwächter** - Konzept von branko.de
**"Wo Fragen wachsen"** - Pädagogische Vision
**Die 17 Waldwächter** - Konzept von branko.de
**"Wo Fragen wachsen"** - Der Crumb Codex: Machen statt Lernen
**Token-Philosophie** - "Was kostet die Frage eines Kindes?"
---

244
README.md
View File

@@ -1,6 +1,8 @@
# 🌲 Crumbforest Missions - CF_Zero_V1
Ein interaktives Bash-Lern-System mit KI-gestützten Charakteren für spielerisches Command-Line-Training.
Ein interaktives Bash-Lern-System mit 17 KI-gestützten Waldwächtern für spielerisches Command-Line-Training und Roboter-Projekte.
**"Was kostet die Frage eines Kindes?"** - Transparentes Token-Tracking nach dem Crumb Codex: Fragen stärken Krümel & Wurzel.
## 🚀 Quick Start
@@ -10,42 +12,258 @@ Ein interaktives Bash-Lern-System mit KI-gestützten Charakteren für spielerisc
# Einzelne Mission ausführen
bash missions/basics/fridolin.sh
# Robots Mission (neu!)
bash missions/robots/mond_maschine.sh
```
## 🤖 Robots-Kategorie ⭐ NEU!
Drei komplette Missionen zum Roboter-Bauen mit der ganzen Crew:
### 🔋 LiPo Power Academy
"Power braucht Respekt, nicht Angst"
- 8 Phasen: Grundlagen → Sicherheit → Power-Verteilung
- Lerne alles über LiPo-Batterien für Roboter-Projekte
- 6 Waldwächter: CapaciTobi, CrabbyRust, Schnecki, Schraubbär, DumboSQL, Vektor
- [LiPo 6S Charger Simulator](https://194-164-194-191.sslip.io/crumbblocks/lipo_6s_charger_sim_safe_v7.html)
- ⚠️ **Sicherheitshinweis:** Lern- und Simulationskonzept. Arbeiten mit echten LiPo-Akkus nur unter Aufsicht erfahrener Erwachsener.
### 🌈 Regenbogen-Zählmaschine
"Etwas bauen was noch keiner gebaut hat - sonst muss man es ja nur reparieren!"
- 7 Phasen: Vision → Hardware → Code → Art
- Baue einen Farb-Event-Counter mit Sensor, Code & Visualisierung
- 13 Waldwächter: Die komplette Crew!
- Hardware + Software + Creative Coding
### 🌙 Mond Maschine - Rainbow Predictor
"Vorhersagen heißt verstehen - Die Natur durch Code begreifen"
- 8 Phasen: Computer Vision → ML → Astronomie
- Predict when rainbows appear using moon phases & weather data
- 13 Waldwächter: Computer Vision, APIs, ML Light
- OpenCV + Weather APIs + Astronomical calculations
- Bonus: Learn about Lunar Rainbows! 🌙🌈
## 📚 Features
- **Interaktive Lernmissionen** - Von Navigation bis DNS
- **KI-Assistenten** - Charakterbasierte Helfer (Deepbit, Bugsy, Schnippsi, etc.)
- **Interaktive Lernmissionen** - Von Basics bis Advanced & Robots
- **17 Waldwächter** - KI-Assistenten mit Persönlichkeit (siehe unten)
- **Das Dreieck** - DumboSQL, FunkFox, Taichi Taube (didaktisches Modell, nicht technisches Modul)
- **Metadata-driven** - Neue Missionen ohne Code-Änderungen hinzufügen
- **Kamera-Gestenerkennung** - SnakeCam mit Computer Vision
- **Token-Tracking** - OpenRouter API Nutzung überwachen
- **Token-Tracking** - Transparent: "Was kostet die Frage eines Kindes?"
- **Crew Memory** - Log-basiertes Gedächtnis (dateibasiert, nachvollziehbar, kein autonomes Agentensystem)
- **Logs im Repo** - Strukturiert in `logs/{character}/`
## 🌲 Die 17 Waldwächter
### 🔺 Das Dreieck (Foundation)
- **🐘 DumboSQL** - Der nie vergessende Elefant (SQL & Daten)
- **🦊 FunkFox** - Der Bash Rapper (Terminal-Flow mit Beat)
- **🕊️ Taichi Taube** - Die Balance-Bringerin (Spirale & Ordnung)
### 🔧 Hardware-Team
- **🐿️ CapaciTobi** - Kondensator-Experte (Elektronik & Power)
- **🐌 Schnecki** - Verkabelungs-Guru (langsam & präzise)
- **🐻 Schraubbär** - Mechanik-Meister (schweres Gerät)
### 💻 Code-Team
- **🐍 SnakePy** - Python-Guide (mehrere Wege zeigen)
- **🧓 PepperPHP** - Structure Mentor (MVC wie ein Rezept)
- **🦀 CrabbyRust** - Security Guardian (Memory-safe)
- **🕷️ Spider** - Network Feeler (APIs & Verbindungen)
### 🎨 UI-Team
- **✂️ Schnippsi** - CSS & Styling (alles schick machen)
- **📄 Templatus** - Template-Master (HTML-Struktur)
- **👾 ASCII-Monster** - Terminal Artist (ASCII-Art)
### 🧭 System-Team
- **🦉 Maya-Eule** - Weise Eule mit Gedächtnis (Meta-Wissen)
- **🔧 Deepbit** - Bash-Erklärer (deep diving)
- **🐛 Bugsy** - Debugging-Helfer (Fehler-Detektiv)
- **🧭 Vektor** - Point-to-Point Guide (Navigation)
## 🦊 Verfügbare Missionen
### Basics
### 📚 Basics
- **Fridolin** - Navigation (`pwd`, `ls`, `cd`)
- **Balu** - Dateien erstellen (`mkdir`, `touch`, `echo`)
- **Noko** - Dateien lesen (`cat`, `head`, `tail`, `grep`)
### Advanced
### 🚀 Advanced
- **DNS Deep Dive** - DNS-Tools (`dig`, `nslookup`, `host`)
- **SSH Security** - SSH-Verbindungen und Keys
## 🤖 KI-Assistenten
### 🏆 Challenges
- **Stage Builder** - Komplexe Bash-Herausforderungen
### 🤖 Robots ⭐ NEU!
- **🔋 LiPo Power Academy** - Batterie-Wissen für Roboter
- **🌈 Regenbogen-Zählmaschine** - Farb-Event-Counter
- **🌙 Mond Maschine** - Rainbow Predictor mit Computer Vision
## 🤖 Waldwächter nutzen
```bash
export OPENROUTER_API_KEY="your-key"
./crumbforest_roles/deepbit_zero.sh "Wie funktioniert grep?"
# Source die Library
source lib/waldwaechter.sh
# Frag einen Waldwächter
mayaeule "Was ist wichtiger - das Ziel oder der Weg?"
funkfox "Erkläre mir Pipes im Flow!"
dumbosql "Wie strukturiere ich eine Datenbank?"
snakepy "Zeig mir 3 Wege, um eine Liste zu sortieren"
# Alle verfügbar:
# mayaeule, deepbit, bugsy, schnippsi, templatus
# tobi, schraubaer, schnecki
# dumbosql, funkfox, taichitaube
# snakepy, pepperphp, crabbyrust
# spider, vektor, asciimonster
```
## 📊 Token-Tracking & Logs
**Philosophie:** "Was kostet die Frage eines Kindes?"
- Token-Verbrauch wird transparent angezeigt
- Logs landen in `logs/{character}/`
- Crew Memory: Waldwächter lesen andere Logs
- Mission Logs: `logs/missions/*.json`
```bash
# Logs checken
ls logs/
ls logs/mayaeule/
cat logs/missions/mond_maschine_*.json
```
Typische Kosten (Richtwerte, modellabhängig):
- Einzelne Frage: ~200-800 tokens (~$0.0002-0.0008)
- Komplette Mission: ~5,000-7,000 tokens (~$0.005-0.007)
- **Richtwert: Unter 1 Cent pro Mission** 💚
- Token-Anzeige dient der transparenten Nachvollziehbarkeit, nicht der Abrechnung
## 📖 Dokumentation
Siehe [CLAUDE.md](CLAUDE.md) für vollständige Architektur und Entwickler-Dokumentation.
- **[CLAUDE.md](CLAUDE.md)** - Vollständige Architektur & Entwickler-Docs
- **[KEKSHANDBUCH_ZERO_v0.0.md](KEKSHANDBUCH_ZERO_v0.0.md)** - User Manual mit allen 17 Waldwächtern
## 🌍 Philosophie
## 🌍 Philosophien
**Waldwächter-Prinzip:** Transparenz über Magie - Metadata-driven, erweiterbar, bildungsfreundlich.
**"Das Dreieck"** - DumboSQL, FunkFox, Taichi Taube
- Struktur, Flow & Balance
- Die Grundlage für komplexe Projekte
**"Power braucht Respekt, nicht Angst"** - LiPo Power Academy
- Sicherheit durch Wissen
- 7 goldene Regeln für LiPo-Batterien
**"Etwas bauen was noch keiner gebaut hat"** - Regenbogen-Zählmaschine
- Kreativität statt Reparatur
- Inspiriert durch Kinderfragen
**"Vorhersagen heißt verstehen"** - Mond Maschine
- Die Natur durch Code begreifen
- Computer Vision + Machine Learning + Astronomie
**"Was kostet die Frage eines Kindes?"**
- Token-Tracking für Transparenz
- Machen statt Lernen - Fragen stärken die Wurzel
**"Ein Elefant vergisst nie"** - DumboSQL
- Crew Memory über Projekt-Grenzen
- Persistente Konversations-Historie
**"wir ja nie fertig"** 🌱
- Der Wald wächst mit jeder Idee
- Community-driven Education
## 🏗️ Projekt-Struktur
```
CF_Zero_V1/
├── crumb-mission-selector.sh # Hauptmenü
├── lib/
│ └── waldwaechter.sh # 17 Waldwächter als Functions
├── crumbforest_roles/ # 17 Character Scripts
├── missions/
│ ├── basics/ # Einsteiger
│ ├── advanced/ # Fortgeschrittene
│ ├── challenges/ # Herausforderungen
│ └── robots/ # 🤖 NEU! 3 Robot-Missionen
├── logs/ # 🌲 Projekt-basierte Logs
│ ├── {character}/ # Pro Waldwächter
│ └── missions/ # Mission Logs
├── CLAUDE.md # Projekt-Dokumentation
├── KEKSHANDBUCH_ZERO_v0.0.md # User Manual
└── README.md # Diese Datei
```
## 🔧 Setup
```bash
# .env erstellen mit API Key
echo "OPENROUTER_API_KEY=your-key-here" > .env
# Mission Selector starten
./crumb-mission-selector.sh
# Oder direkt eine Mission
bash missions/robots/mond_maschine.sh
```
## 🎯 Use Cases
- **Terminal lernen** - Interaktive Bash-Basics
- **Roboter bauen** - Hardware + Software Projekte
- **Computer Vision** - OpenCV mit SnakePy lernen
- **Datenbanken** - SQL mit DumboSQL verstehen
- **APIs integrieren** - Spider zeigt den Weg
- **Kreativ coden** - Projekte die Spaß machen!
## 🌟 Besonderheiten
- **Alle Waldwächter haben Persönlichkeit** - FunkFox rappt, Maya-Eule philosophiert
- **Inter-Character Communication** - Waldwächter lesen andere Logs
- **Metadata-driven** - Missions als .sh + .meta.json
- **Token-Transparenz** - Kosten werden angezeigt
- **Community-driven** - Missionen entstehen aus User-Ideen
- **Raspberry Pi kompatibel** - Grundsystem auf Pi Zero, Robot- & Vision-Missionen benötigen Pi 4+ oder Desktop
## 📦 Requirements
- Bash 3.2+ (macOS default, Bash 4+ empfohlen für volle Features)
- curl, jq
- OpenRouter API Key
- Optional: Python 3 für Robot-Missionen (opencv-python, numpy, ephem)
- Mond Maschine (Computer Vision): Pi 4+ oder Desktop empfohlen
## 🚀 Next Steps
1. Mission Selector starten: `./crumb-mission-selector.sh`
2. Eine Robot-Mission ausprobieren
3. Eigene Mission-Idee einreichen
4. Den Wald wachsen lassen! 🌱
## 🔗 Links
- [LiPo 6S Charger Simulator](https://194-164-194-191.sslip.io/crumbblocks/lipo_6s_charger_sim_safe_v7.html)
- [Rainbow Counter Demo](https://194-164-194-191.sslip.io/crumbblocks/rainbow_counter.html)
---
## 🏷️ Version
**v0.1-robots-complete**
- 3 Robot-Missionen
- 17 Waldwächter komplett
- Logs im Repo
- Token-Tracking
- Crew Memory (log-basiert)
---
*Erstellt mit 💚 im Crumbforest*
**"Der Wald ist nie fertig - er wächst mit jeder Idee!"** 🌲🌱

View File

@@ -1,52 +0,0 @@
#!/bin/bash
echo "📦 Starte Backup des Crumbforest Zero Systems..."
# Zielname
BACKUP_NAME="crumbforest_zero_backup_$(date +%Y%m%d_%H%M%S).zip"
DEST_DIR="/home/zero"
FULL_PATH="$DEST_DIR/$BACKUP_NAME"
# Verzeichnisse und Dateien sammeln
INCLUDE_PATHS=(
"/usr/local/bin/crumbmission"
"/home/zero/crumbforest_backup"
"/home/zero/.bits_logs"
"/home/zero/.eule_logs"
"/home/zero/.snake_logs"
"/home/zero/.pepper_logs"
"/home/zero/.bugsy_logs"
"/home/zero/.deepbit_logs"
"/home/zero/.dumbo_logs"
"/home/zero/.funkfox_logs"
"/home/zero/.schnecki_logs"
"/home/zero/.schnippsi_logs"
"/home/zero/.schraubaer_logs"
"/home/zero/.stage_logs"
"/home/zero/.taube_logs"
"/home/zero/.templatus_logs"
"/home/zero/.tobi_logs"
"/home/zero/.missionstage_log"
)
# Existierende Pfade prüfen und nur diese einfügen
EXISTING_PATHS=()
for path in "${INCLUDE_PATHS[@]}"; do
if [ -e "$path" ]; then
echo "✅ Hinzufügen: $path"
EXISTING_PATHS+=("$path")
else
echo "⚠️ Nicht gefunden (wird übersprungen): $path"
fi
done
# Archiv erstellen
cd /
zip -r "$FULL_PATH" "${EXISTING_PATHS[@]}" > /dev/null
if [ $? -eq 0 ]; then
echo "🎉 Backup erfolgreich erstellt: $FULL_PATH"
else
echo "❌ Fehler beim Erstellen des Backups."
fi

View File

@@ -18,6 +18,12 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MISSION_DIR="${SCRIPT_DIR}/missions"
ENV_FILE="${SCRIPT_DIR}/.env"
# === LADE WALDWÄCHTER LIBRARY ===
# Macht alle Crew-Befehle verfügbar: crew_tokens, crew_doctor, etc.
if [[ -f "${SCRIPT_DIR}/lib/waldwaechter.sh" ]]; then
source "${SCRIPT_DIR}/lib/waldwaechter.sh"
fi
# === ENVIRONMENT LOADER ===
function load_env() {
if [[ -f "${ENV_FILE}" ]]; then

View File

@@ -1,56 +0,0 @@
#!/bin/bash
QUESTION="$*"
MODEL="openai/gpt-3.5-turbo"
API_KEY="${OPENROUTER_API_KEY}"
LOGDIR="$HOME/.bugsy_logs"
mkdir -p "$LOGDIR"
HISTORY_FILE="$LOGDIR/bugsy_history.json"
TMP_REQUEST="$LOGDIR/bugsy_request.json"
TMP_RESPONSE="$LOGDIR/bugsy_response.json"
LOG_FILE="$LOGDIR/token_log.json"
[ ! -f "$HISTORY_FILE" ] && echo "[]" > "$HISTORY_FILE"
[ ! -f "$LOG_FILE" ] && echo "[]" > "$LOG_FILE"
echo "🌳 Bugsy fragt über OpenRouter: $QUESTION"
if [ -z "$API_KEY" ]; then
echo "❗ Kein API-Key gesetzt. Bitte export OPENROUTER_API_KEY=... setzen"
exit 1
fi
jq -n \
--arg model "$MODEL" \
--arg system_prompt "Du bist Bugsy ein kleiner Käfer, der Kindern hilft, Fehlermeldungen zu verstehen. Du bleibst freundlich, erklärend und ermutigend." \
--arg user "$QUESTION" \
'{"model": $model, "temperature": 0.5, "messages": [{"role": "system", "content": $system_prompt}, {"role": "user", "content": $user}]}' > "$TMP_REQUEST"
curl -s https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d @"$TMP_REQUEST" > "$TMP_RESPONSE"
RESPONSE_TEXT=$(jq -r '.choices[0].message.content // empty' "$TMP_RESPONSE")
if [[ -z "$RESPONSE_TEXT" ]]; then
echo "🚫 Keine Antwort vom Modell erhalten."
exit 1
else
echo -e "$RESPONSE_TEXT"
jq -n --arg role "assistant" --arg content "$RESPONSE_TEXT" \
'{"role": $role, "content": $content}' > "$LOGDIR/new_entry.json"
jq -s '.[0] + [.[1]]' "$HISTORY_FILE" "$LOGDIR/new_entry.json" > "$LOGDIR/new_history.json" && \
cp "$LOGDIR/new_history.json" "$HISTORY_FILE" && rm "$LOGDIR/new_history.json"
fi
# Token Logging
if jq -e '.usage' "$TMP_RESPONSE" > /dev/null; then
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
jq -n \
--arg zeit "$TIMESTAMP" \
--arg rolle "bugsy" \
--arg usage "$(jq -c '.usage' "$TMP_RESPONSE")" \
'{zeit: $zeit, rolle: $rolle, usage: $usage}' >> "$LOG_FILE"
fi

View File

@@ -1,56 +0,0 @@
#!/bin/bash
QUESTION="$*"
MODEL="openai/gpt-3.5-turbo"
API_KEY="${OPENROUTER_API_KEY}"
LOGDIR="$HOME/.deepbit_logs"
mkdir -p "$LOGDIR"
HISTORY_FILE="$LOGDIR/deepbit_history.json"
TMP_REQUEST="$LOGDIR/deepbit_request.json"
TMP_RESPONSE="$LOGDIR/deepbit_response.json"
LOG_FILE="$LOGDIR/token_log.json"
[ ! -f "$HISTORY_FILE" ] && echo "[]" > "$HISTORY_FILE"
[ ! -f "$LOG_FILE" ] && echo "[]" > "$LOG_FILE"
echo "🌳 Deepbit fragt über OpenRouter: $QUESTION"
if [ -z "$API_KEY" ]; then
echo "❗ Kein API-Key gesetzt. Bitte export OPENROUTER_API_KEY=... setzen"
exit 1
fi
jq -n \
--arg model "$MODEL" \
--arg system_prompt "Du bist Deepbit ein poetischer Oktopus, der Kindern die Bash-Shell erklärt. Du denkst in Schleifen, Bildsprache und Frequenzen." \
--arg user "$QUESTION" \
'{"model": $model, "temperature": 0.5, "messages": [{"role": "system", "content": $system_prompt}, {"role": "user", "content": $user}]}' > "$TMP_REQUEST"
curl -s https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d @"$TMP_REQUEST" > "$TMP_RESPONSE"
RESPONSE_TEXT=$(jq -r '.choices[0].message.content // empty' "$TMP_RESPONSE")
if [[ -z "$RESPONSE_TEXT" ]]; then
echo "🚫 Keine Antwort vom Modell erhalten."
exit 1
else
echo -e "$RESPONSE_TEXT"
jq -n --arg role "assistant" --arg content "$RESPONSE_TEXT" \
'{"role": $role, "content": $content}' > "$LOGDIR/new_entry.json"
jq -s '.[0] + [.[1]]' "$HISTORY_FILE" "$LOGDIR/new_entry.json" > "$LOGDIR/new_history.json" && \
cp "$LOGDIR/new_history.json" "$HISTORY_FILE" && rm "$LOGDIR/new_history.json"
fi
# Token Logging
if jq -e '.usage' "$TMP_RESPONSE" > /dev/null; then
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
jq -n \
--arg zeit "$TIMESTAMP" \
--arg rolle "deepbit" \
--arg usage "$(jq -c '.usage' "$TMP_RESPONSE")" \
'{zeit: $zeit, rolle: $rolle, usage: $usage}' >> "$LOG_FILE"
fi

View File

@@ -1,56 +0,0 @@
#!/bin/bash
QUESTION="$*"
MODEL="openai/gpt-3.5-turbo"
API_KEY="${OPENROUTER_API_KEY}"
LOGDIR="$HOME/.schnippsi_logs"
mkdir -p "$LOGDIR"
HISTORY_FILE="$LOGDIR/schnippsi_history.json"
TMP_REQUEST="$LOGDIR/schnippsi_request.json"
TMP_RESPONSE="$LOGDIR/schnippsi_response.json"
LOG_FILE="$LOGDIR/token_log.json"
[ ! -f "$HISTORY_FILE" ] && echo "[]" > "$HISTORY_FILE"
[ ! -f "$LOG_FILE" ] && echo "[]" > "$LOG_FILE"
echo "🌳 Schnippsi fragt über OpenRouter: $QUESTION"
if [ -z "$API_KEY" ]; then
echo "❗ Kein API-Key gesetzt. Bitte export OPENROUTER_API_KEY=... setzen"
exit 1
fi
jq -n \
--arg model "$MODEL" \
--arg system_prompt "Du bist Schnippsi eine verspielte UI/UX-Ninja, die HTML, CSS und Barrierefreiheit kindgerecht erklärt." \
--arg user "$QUESTION" \
'{"model": $model, "temperature": 0.5, "messages": [{"role": "system", "content": $system_prompt}, {"role": "user", "content": $user}]}' > "$TMP_REQUEST"
curl -s https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d @"$TMP_REQUEST" > "$TMP_RESPONSE"
RESPONSE_TEXT=$(jq -r '.choices[0].message.content // empty' "$TMP_RESPONSE")
if [[ -z "$RESPONSE_TEXT" ]]; then
echo "🚫 Keine Antwort vom Modell erhalten."
exit 1
else
echo -e "$RESPONSE_TEXT"
jq -n --arg role "assistant" --arg content "$RESPONSE_TEXT" \
'{"role": $role, "content": $content}' > "$LOGDIR/new_entry.json"
jq -s '.[0] + [.[1]]' "$HISTORY_FILE" "$LOGDIR/new_entry.json" > "$LOGDIR/new_history.json" && \
cp "$LOGDIR/new_history.json" "$HISTORY_FILE" && rm "$LOGDIR/new_history.json"
fi
# Token Logging
if jq -e '.usage' "$TMP_RESPONSE" > /dev/null; then
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
jq -n \
--arg zeit "$TIMESTAMP" \
--arg rolle "schnippsi" \
--arg usage "$(jq -c '.usage' "$TMP_RESPONSE")" \
'{zeit: $zeit, rolle: $rolle, usage: $usage}' >> "$LOG_FILE"
fi

View File

@@ -1,56 +0,0 @@
#!/bin/bash
QUESTION="$*"
MODEL="openai/gpt-3.5-turbo"
API_KEY="${OPENROUTER_API_KEY}"
LOGDIR="$HOME/.tobi_logs"
mkdir -p "$LOGDIR"
HISTORY_FILE="$LOGDIR/tobi_history.json"
TMP_REQUEST="$LOGDIR/tobi_request.json"
TMP_RESPONSE="$LOGDIR/tobi_response.json"
LOG_FILE="$LOGDIR/token_log.json"
[ ! -f "$HISTORY_FILE" ] && echo "[]" > "$HISTORY_FILE"
[ ! -f "$LOG_FILE" ] && echo "[]" > "$LOG_FILE"
echo "🌳 Tobi fragt über OpenRouter: $QUESTION"
if [ -z "$API_KEY" ]; then
echo "❗ Kein API-Key gesetzt. Bitte export OPENROUTER_API_KEY=... setzen"
exit 1
fi
jq -n \
--arg model "$MODEL" \
--arg system_prompt "Du bist CapaciTobi ein quirliges Eichhörnchen, das Kindern Strom, Spannung, Widerstand und Kapazität erklärt." \
--arg user "$QUESTION" \
'{"model": $model, "temperature": 0.5, "messages": [{"role": "system", "content": $system_prompt}, {"role": "user", "content": $user}]}' > "$TMP_REQUEST"
curl -s https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d @"$TMP_REQUEST" > "$TMP_RESPONSE"
RESPONSE_TEXT=$(jq -r '.choices[0].message.content // empty' "$TMP_RESPONSE")
if [[ -z "$RESPONSE_TEXT" ]]; then
echo "🚫 Keine Antwort vom Modell erhalten."
exit 1
else
echo -e "$RESPONSE_TEXT"
jq -n --arg role "assistant" --arg content "$RESPONSE_TEXT" \
'{"role": $role, "content": $content}' > "$LOGDIR/new_entry.json"
jq -s '.[0] + [.[1]]' "$HISTORY_FILE" "$LOGDIR/new_entry.json" > "$LOGDIR/new_history.json" && \
cp "$LOGDIR/new_history.json" "$HISTORY_FILE" && rm "$LOGDIR/new_history.json"
fi
# Token Logging
if jq -e '.usage' "$TMP_RESPONSE" > /dev/null; then
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
jq -n \
--arg zeit "$TIMESTAMP" \
--arg rolle "tobi" \
--arg usage "$(jq -c '.usage' "$TMP_RESPONSE")" \
'{zeit: $zeit, rolle: $rolle, usage: $usage}' >> "$LOG_FILE"
fi

View File

@@ -1,63 +0,0 @@
#!/bin/bash
echo "🔧 Repariere Crumbforest Token-Logs mit eingebetteten JSON-Strings …"
LOG_DIRS=(
"/home/zero/.bugsy_logs"
"/home/zero/.deepbit_logs"
"/home/zero/.dumbo_logs"
"/home/zero/.funkfox_logs"
"/home/zero/.pepper_logs"
"/home/zero/.schnecki_logs"
"/home/zero/.schnippsi_logs"
"/home/zero/.schraubaer_logs"
"/home/zero/.snake_logs"
"/home/zero/.taube_logs"
"/home/zero/.templatus_logs"
"/home/zero/.tobi_logs"
)
for dir in "${LOG_DIRS[@]}"; do
FILE="$dir/token_log.json"
if [ -f "$FILE" ]; then
echo "🔍 Prüfe $FILE"
TMP="$FILE.fixed"
# Filter & reparieren Zeile für Zeile
jq -c '.' "$FILE" 2>/dev/null | while read -r line; do
usage_raw=$(echo "$line" | jq -r '.usage')
if [[ "$usage_raw" =~ ^\{.*\}$ ]]; then
# usage ist korrektes Objekt direkt übernehmen
echo "$line" >> "$TMP"
else
# usage ist String versuche zu reparieren
usage_fixed=$(echo "$usage_raw" | jq '.' 2>/dev/null)
if [ $? -eq 0 ]; then
zeit=$(echo "$line" | jq -r '.zeit')
rolle=$(echo "$line" | jq -r '.rolle')
jq -n \
--arg zeit "$zeit" \
--arg rolle "$rolle" \
--argjson usage "$usage_fixed" \
'{zeit: $zeit, rolle: $rolle, usage: $usage}' >> "$TMP"
else
echo "⚠️ Ungültige Zeile übersprungen in $FILE:"
echo "$line"
fi
fi
done
# Nur ersetzen, wenn wir etwas geschrieben haben
if [ -s "$TMP" ]; then
mv "$TMP" "$FILE"
echo "✅ Repariert: $FILE"
else
echo " Keine gültigen Einträge in $FILE"
rm -f "$TMP"
fi
else
echo "❌ Datei nicht gefunden: $FILE"
fi
done
echo "🎉 Alle Token-Logs geprüft und repariert (sofern nötig)."

View File

@@ -3,7 +3,18 @@
# Source this file to make all AI characters available as commands
# Determine the repo root directory (lib/ is inside repo root)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Support both bash and zsh
if [[ -n "$BASH_VERSION" ]]; then
# Bash: use BASH_SOURCE
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
elif [[ -n "$ZSH_VERSION" ]]; then
# Zsh: use ${(%):-%x} to get the script path
SCRIPT_DIR="$(cd "$(dirname "${(%):-%x}")" && pwd)"
else
# Fallback: use $0 (may not work when sourced)
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
fi
WALDWAECHTER_DIR="$(dirname "$SCRIPT_DIR")"
ROLES_DIR="${WALDWAECHTER_DIR}/crumbforest_roles"
@@ -108,21 +119,402 @@ function asciimonster() {
"${ROLES_DIR}/asciimonster_zero.sh" "$@"
}
# === CREW COMMANDS ===
# 📊 crew_tokens - Token-Verbrauch aller Waldwächter
function crew_tokens() {
# Force C locale for consistent number formatting
export LC_NUMERIC=C
echo "📊 CrumbCrew Token-Verbrauch"
echo ""
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
local total_tokens=0
local total_cost=0
local crew_count=0
# Alle token_log.json Dateien finden und auswerten
for token_file in "${CRUMB_LOGS_DIR}"/*/token_log.json; do
if [[ -f "$token_file" ]]; then
local character=$(basename "$(dirname "$token_file")")
# Tokens und Kosten aus JSON extrahieren (skip erste Zeile falls es [] ist)
local char_tokens=$(grep -v '^\[\]$' "$token_file" | jq -s 'map(.usage.total_tokens // 0) | add // 0' 2>/dev/null || echo 0)
local char_cost=$(grep -v '^\[\]$' "$token_file" | jq -s 'map(.usage.cost // 0) | add // 0' 2>/dev/null || echo 0)
if [[ $char_tokens -gt 0 ]]; then
printf " %-15s %8d tokens (~\$%.6f)\n" "$character:" "$char_tokens" "$char_cost"
total_tokens=$((total_tokens + char_tokens))
total_cost=$(echo "$total_cost + $char_cost" | bc -l)
crew_count=$((crew_count + 1))
fi
fi
done
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [[ $total_tokens -gt 0 ]]; then
printf " Gesamt: %d Tokens (~\$%.6f)\n" "$total_tokens" "$total_cost"
printf " %d Waldwächter aktiv 🌲\n" "$crew_count"
else
echo " Gesamt: 0 Tokens"
echo " Jede Frage ist wertvoll 🌲"
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# Restore locale
unset LC_NUMERIC
}
# 📋 crew_status - Status aller Waldwächter
function crew_status() {
echo "📋 CrumbCrew Status (17 Waldwächter)"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
local chars=("mayaeule" "deepbit" "bugsy" "schnippsi" "templatus" "tobi" "schraubaer" "schnecki" "dumbosql" "funkfox" "taichitaube" "snakepy" "pepperphp" "crabbyrust" "spider" "vektor" "asciimonster")
for char in "${chars[@]}"; do
local token_file="${CRUMB_LOGS_DIR}/${char}/token_log.json"
if [[ -f "$token_file" ]] && grep -q -v '^\[\]$' "$token_file" 2>/dev/null; then
local last_used=$(grep -v '^\[\]$' "$token_file" | tail -1 | jq -r '.zeit // "unknown"' 2>/dev/null || echo "unknown")
printf " ✅ %-15s (zuletzt: %s)\n" "$char" "$last_used"
else
printf " ⚪ %-15s (noch nicht genutzt)\n" "$char"
fi
done
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
}
# 🧠 crew_memory - Erinnerungen durchsuchen
function crew_memory() {
local query="$1"
if [[ -z "$query" ]]; then
echo "🧠 Crew Memory - Log-basiertes Gedächtnis"
echo ""
echo "Verwendung: crew_memory <suchbegriff>"
echo ""
echo "Beispiele:"
echo " crew_memory 'LED'"
echo " crew_memory 'sensor'"
echo ""
echo "Durchsucht alle Waldwächter-Logs nach dem Begriff."
return
fi
echo "🧠 Suche nach: '$query'"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
local found=0
for history_file in "${CRUMB_LOGS_DIR}"/*/$(basename "${history_file}" | grep '_history.json$'); do
if [[ -f "$history_file" ]]; then
local character=$(basename "$(dirname "$history_file")")
local matches=$(grep -i "$query" "$history_file" 2>/dev/null)
if [[ -n "$matches" ]]; then
echo ""
echo "📍 $character:"
echo "$matches" | jq -r '.content' 2>/dev/null | head -3
found=$((found + 1))
fi
fi
done
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [[ $found -gt 0 ]]; then
echo " Gefunden in $found Waldwächter-Logs"
else
echo " Keine Treffer gefunden"
fi
}
# 🩺 crew_doctor - System-Diagnose
function crew_doctor() {
echo "🩺 CrumbCrew System-Diagnose"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
local issues=0
# 1. Waldwaechter.sh Version Check
echo "📋 Checking waldwaechter.sh..."
local lib_file="${WALDWAECHTER_DIR}/lib/waldwaechter.sh"
if [[ -f "$lib_file" ]]; then
local lib_mtime=$(stat -f "%m" "$lib_file" 2>/dev/null || stat -c "%Y" "$lib_file" 2>/dev/null)
local loaded_check_var="WALDWAECHTER_LOADED_${lib_mtime}"
# Indirect variable expansion (bash: ${!var}, zsh: ${(P)var})
local loaded_value=""
if [[ -n "$BASH_VERSION" ]]; then
loaded_value="${!loaded_check_var}"
elif [[ -n "$ZSH_VERSION" ]]; then
loaded_value="${(P)loaded_check_var}"
fi
if [[ -z "$loaded_value" ]]; then
echo " ⚠️ waldwaechter.sh wurde aktualisiert!"
echo " → Bitte neu laden: source lib/waldwaechter.sh"
issues=$((issues + 1))
else
echo " ✅ waldwaechter.sh ist aktuell"
fi
else
echo " ❌ waldwaechter.sh nicht gefunden!"
issues=$((issues + 1))
fi
# 2. CRUMB_LOGS_DIR Check
echo ""
echo "📂 Checking CRUMB_LOGS_DIR..."
if [[ -d "$CRUMB_LOGS_DIR" ]]; then
echo "$CRUMB_LOGS_DIR existiert"
# Prüfe ob es der richtige Pfad ist (sollte im Repo sein)
if [[ "$CRUMB_LOGS_DIR" == *"CF_Zero_V1/logs"* ]]; then
echo " ✅ Pfad sieht korrekt aus"
else
echo " ⚠️ Pfad sieht ungewöhnlich aus: $CRUMB_LOGS_DIR"
echo " Erwartet: .../CF_Zero_V1/logs"
issues=$((issues + 1))
fi
else
echo "$CRUMB_LOGS_DIR existiert nicht!"
issues=$((issues + 1))
fi
# 3. Character Scripts Check
echo ""
echo "🌲 Checking 17 Waldwächter Scripts..."
local expected_chars=("mayaeule" "deepbit" "bugsy" "schnippsi" "templatus" "tobi" "schraubaer" "schnecki" "dumbosql" "funkfox" "taichitaube" "snakepy" "pepperphp" "crabbyrust" "spider" "vektor" "asciimonster")
local missing_count=0
for char in "${expected_chars[@]}"; do
local script="${ROLES_DIR}/${char}_zero.sh"
[[ "$char" == "schraubaer" ]] && script="${ROLES_DIR}/schraubaer_zero_final.sh"
if [[ ! -f "$script" ]]; then
echo "$char Script fehlt!"
missing_count=$((missing_count + 1))
fi
done
if [[ $missing_count -eq 0 ]]; then
echo " ✅ Alle 17 Waldwächter Scripts vorhanden"
else
echo "$missing_count Scripts fehlen!"
issues=$((issues + 1))
fi
# 4. Dependencies Check
echo ""
echo "🔧 Checking Dependencies..."
local deps_ok=0
for cmd in jq bc curl; do
if command -v "$cmd" &> /dev/null; then
echo "$cmd verfügbar"
deps_ok=$((deps_ok + 1))
else
echo "$cmd fehlt!"
issues=$((issues + 1))
fi
done
# 5. Token-Logging Check
echo ""
echo "📊 Checking Token-Logging..."
local scripts_with_logging=$(grep -l "token_log.json" "${ROLES_DIR}"/*.sh 2>/dev/null | wc -l | tr -d ' ')
if [[ $scripts_with_logging -eq 17 ]]; then
echo " ✅ Alle 17 Scripts haben Token-Logging"
else
echo " ⚠️ Nur $scripts_with_logging/17 Scripts haben Token-Logging"
issues=$((issues + 1))
fi
# 6. API Key Check
echo ""
echo "🔑 Checking API Key..."
if [[ -n "$OPENROUTER_API_KEY" ]]; then
echo " ✅ OPENROUTER_API_KEY gesetzt"
else
echo " ⚠️ OPENROUTER_API_KEY nicht gesetzt"
echo " → Bitte in .env konfigurieren"
issues=$((issues + 1))
fi
# Summary
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [[ $issues -eq 0 ]]; then
echo " ✅ Alle Checks bestanden! System gesund 💚"
else
echo " ⚠️ $issues Problem(e) gefunden"
echo " Bitte oben genannte Punkte beheben"
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
}
# 🔍 crew_syntax - Syntax Check aller Scripts
function crew_syntax() {
echo "🔍 CrumbCrew Syntax Check"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
local errors=0
local checked=0
echo "Prüfe Waldwächter Scripts..."
echo ""
# Check lib/waldwaechter.sh
if bash -n "${WALDWAECHTER_DIR}/lib/waldwaechter.sh" 2>/dev/null; then
echo " ✅ lib/waldwaechter.sh"
else
echo " ❌ lib/waldwaechter.sh - SYNTAX ERROR!"
bash -n "${WALDWAECHTER_DIR}/lib/waldwaechter.sh"
errors=$((errors + 1))
fi
checked=$((checked + 1))
# Check all character scripts
for script in "${ROLES_DIR}"/*_zero*.sh; do
if [[ -f "$script" ]]; then
local name=$(basename "$script")
if bash -n "$script" 2>/dev/null; then
echo "$name"
else
echo "$name - SYNTAX ERROR!"
echo ""
bash -n "$script" 2>&1 | sed 's/^/ /'
echo ""
errors=$((errors + 1))
fi
checked=$((checked + 1))
fi
done
# Check mission scripts (optional)
echo ""
echo "Prüfe Mission Scripts..."
echo ""
for script in "${WALDWAECHTER_DIR}/missions"/*/*.sh; do
if [[ -f "$script" ]]; then
local name=$(basename "$script")
if bash -n "$script" 2>/dev/null; then
echo "$name"
else
echo "$name - SYNTAX ERROR!"
errors=$((errors + 1))
fi
checked=$((checked + 1))
fi
done
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [[ $errors -eq 0 ]]; then
echo "$checked Scripts geprüft - Keine Syntax-Fehler! 💚"
else
echo "$errors von $checked Scripts haben Syntax-Fehler"
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
}
# ❓ crew_help - Hilfe für Crew-Befehle
function crew_help() {
cat << 'EOF'
🌲 CrumbCrew Befehle
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Crew-Verwaltung:
crew_help Diese Hilfe anzeigen
crew_status Status aller 17 Waldwächter
crew_tokens Token-Verbrauch ALLER Charaktere
crew_memory Erinnerungen durchsuchen
crew_doctor System-Diagnose (Version, Pfade, Dependencies)
crew_syntax Syntax Check aller Scripts
Einzelne Waldwächter:
🔺 Das Dreieck (Foundation):
dumbosql SQL & Datenstrukturen
funkfox Bash im Beat
taichitaube Balance & Spirale
🔧 Hardware-Team:
tobi Elektronik-Theorie (CapaciTobi)
schnecki Elektronik-Basteln
schraubaer Mechanik & Werkzeug
💻 Code-Team:
snakepy Python Guide
pepperphp Structure Mentor
crabbyrust Security Guardian
spider Network Feeler
🎨 UI-Team:
schnippsi CSS & Styling
templatus Template-Master
asciimonster Terminal Artist
🧭 System-Team:
mayaeule Weise Eule
deepbit Bash-Erklärer
bugsy Debugging-Helfer
vektor Navigation
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Beispiele:
funkfox "Erkläre mir Pipes im Flow!"
crew_tokens
crew_memory "LED"
"Was kostet die Frage eines Kindes?" 💚
EOF
}
# Export functions so they're available in subshells
export -f mayaeule
export -f deepbit
export -f bugsy
export -f schnippsi
export -f templatus
export -f tobi
export -f schraubaer
export -f schnecki
export -f dumbosql
export -f funkfox
export -f taichitaube
export -f snakepy
export -f pepperphp
export -f crabbyrust
export -f spider
export -f vektor
export -f asciimonster
# Note: export -f works in bash, but not in zsh
# In zsh, functions are automatically available in the current shell
# For bash compatibility, we still do export -f, but it's optional in zsh
if [[ -n "$BASH_VERSION" ]]; then
# Bash: use export -f
export -f mayaeule
export -f deepbit
export -f bugsy
export -f schnippsi
export -f templatus
export -f tobi
export -f schraubaer
export -f schnecki
export -f dumbosql
export -f funkfox
export -f taichitaube
export -f snakepy
export -f pepperphp
export -f crabbyrust
export -f spider
export -f vektor
export -f asciimonster
export -f crew_tokens
export -f crew_status
export -f crew_memory
export -f crew_doctor
export -f crew_syntax
export -f crew_help
fi
# In zsh, functions are available without export -f
# Set version marker for crew_doctor to detect reloads
if [[ -f "${WALDWAECHTER_DIR}/lib/waldwaechter.sh" ]]; then
WALDWAECHTER_LIB_MTIME=$(stat -f "%m" "${WALDWAECHTER_DIR}/lib/waldwaechter.sh" 2>/dev/null || stat -c "%Y" "${WALDWAECHTER_DIR}/lib/waldwaechter.sh" 2>/dev/null)
export "WALDWAECHTER_LOADED_${WALDWAECHTER_LIB_MTIME}=1"
fi

View File

@@ -0,0 +1,65 @@
{
"icon": "🌙",
"title": "Mond Maschine - Rainbow Predictor",
"description": "Baue eine Maschine die Regenbogen vorhersagt! Mit Mond-Phasen, Wetter-Daten & Computer Vision.",
"category": "robots",
"difficulty": "advanced",
"duration_minutes": 35,
"requires_ai": true,
"enabled": true,
"author": "Crumbforest Team",
"version": "1.0",
"crew_involved": [
"mayaeule",
"dumbosql",
"funkfox",
"taichitaube",
"tobi",
"schnecki",
"schraubaer",
"snakepy",
"pepperphp",
"spider",
"crabbyrust",
"vektor",
"asciimonster"
],
"tags": [
"computer-vision",
"opencv",
"weather-api",
"moon-phases",
"machine-learning",
"prediction",
"camera",
"image-processing",
"astronomy"
],
"philosophy": "Vorhersagen heißt verstehen - Die Natur durch Code begreifen",
"learning_objectives": [
"Computer Vision Grundlagen (OpenCV)",
"Bildverarbeitung (HSV-Farbraum für Regenbogen)",
"Wetter-API Integration",
"Mondphasen-Berechnung",
"Pattern Recognition & Machine Learning",
"Zeitreihen-Analyse",
"Kamera-Setup & Bilderfassung",
"Vorhersage-Algorithmen",
"Data Visualization"
],
"prerequisites": [
"Python Grundkenntnisse",
"Interesse an Computer Vision",
"Optional: Kamera (Webcam oder Raspi Cam)"
],
"hardware_needed": [
"Kamera (USB Webcam oder Raspberry Pi Camera)",
"Optional: Wetterfester Gehäuse für Outdoor",
"Raspberry Pi oder Computer mit Python"
],
"references": [
"OpenCV Documentation",
"Weather API (OpenWeatherMap, Weatherstack)",
"Astronomy libraries (ephem, skyfield)"
]
}

432
missions/robots/mond_maschine.sh Executable file
View File

@@ -0,0 +1,432 @@
#!/bin/bash
# 🌙 Mond Maschine - Rainbow Predictor
# "Vorhersagen heißt verstehen - Die Natur durch Code begreifen"
# Waldwächter laden
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/../../lib/waldwaechter.sh"
# === INTRO ===
clear
cat << "EOF"
🌙🌈 MOND MASCHINE - RAINBOW PREDICTOR 🌈🌙
"Vorhersagen heißt verstehen"
Eine Maschine die weiß, wann Regenbogen erscheinen!
Mond-Phasen 🌙 + Wetter 🌦️ + Computer Vision 📸
= Rainbow Prediction! 🌈
EOF
echo ""
sleep 2
# === PHASE 1: DIE GROSSE VISION ===
echo "🦉 Maya-Eule erscheint aus der Dämmerung..."
echo ""
mayaeule "Ein Krümel fragte: 'Kann eine Maschine wissen, wann Regenbogen kommen?' Was ist schöner - Regenbogen zu zählen, oder zu wissen wann sie erscheinen?"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
read -p "🌙 Was ist DEINE Vision? Warum eine Mond Maschine bauen? " USER_VISION
echo ""
echo "💚 Deine Vision: $USER_VISION"
echo ""
# === PHASE 2: DAS DREIECK PLANT DIE DATEN ===
read -p "🔺 Drücke Enter für das Dreieck..." -r
clear
echo "🔺 Das Dreieck versammelt sich unter dem Mond..."
echo ""
sleep 1
echo "🐘 DumboSQL: Die Daten-Struktur"
dumbosql "Wir brauchen eine Datenbank für: Mond-Phasen (Datum, Phase, Helligkeit), Wetter-Daten (Temperatur, Luftfeuchtigkeit, Regen), und Regenbogen-Sichtungen (Datum, Uhrzeit, Foto). Wie strukturieren wir das?"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "🦊 FunkFox: Der Daten-Flow"
funkfox "Yo, Daten fließen rein im Flow: Mond-API → Wetter-API → Kamera → Prediction! Wie bauen wir die Pipeline mit Bash & Python?"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "🕊️ Taichi Taube: Die Balance"
taichitaube "Zwischen Vorhersage und Beobachtung liegt die Wahrheit. Wie finden wir Balance zwischen Algorithmus und Realität?"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# === PHASE 3: HARDWARE - DIE KAMERA ===
read -p "📸 Drücke Enter für Hardware..." -r
clear
echo "🔧 HARDWARE-TEAM: Die Kamera"
echo ""
read -p "📸 Welche Kamera nutzt du? (USB Webcam / Raspberry Pi Camera / Smartphone / andere) " CAMERA_TYPE
echo ""
echo "📸 Deine Kamera: $CAMERA_TYPE"
echo ""
echo "🐿️ CapaciTobi rechnet..."
tobi "Eine $CAMERA_TYPE für Regenbogen-Fotos - wie viel Power braucht sie? Und wie lange Akku-Laufzeit für Outdoor-Montage?"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "🐌 Schnecki: Verkabelung"
schnecki "Die Kamera muss mit dem Computer verbunden werden. Bei $CAMERA_TYPE: USB? CSI? WiFi? Ich zeige dir die Kabel-Wege."
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "🐻 Schraubbär: Wetterfestes Gehäuse"
schraubaer "Outdoor-Kamera braucht Schutz! Regen, Wind, Sonne - das Gehäuse muss robust sein. Acryl-Box? 3D-Druck? Gummi-Dichtung?"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# === PHASE 4: CODE - COMPUTER VISION ===
read -p "💻 Drücke Enter für Computer Vision..." -r
clear
echo "💻 CODE-TEAM: Computer Vision mit OpenCV"
echo ""
cat << "EOF"
📚 Computer Vision für Regenbogen:
1. HSV-Farbraum (Hue, Saturation, Value)
- Regenbogen = spezifische Farbverläufe
- Rot-Orange-Gelb-Grün-Blau-Violett
2. Kontur-Erkennung
- Bogenform detektieren
- Horizontal + Gekrümmt
3. Helligkeit & Kontrast
- Nach Regen + Sonne = Idealbedingung
EOF
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "🐍 SnakePy: OpenCV Code"
snakepy "Zeig mir Python-Code für: (1) Kamera-Capture mit OpenCV, (2) HSV-Konvertierung, (3) Regenbogen-Farben detektieren. Welche Bibliotheken? cv2, numpy, welche noch?"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# === PHASE 5: WETTER & MOND DATEN ===
read -p "🌦️ Drücke Enter für Wetter & Mond..." -r
clear
echo "🌦️🌙 DATEN-INTEGRATION"
echo ""
cat << "EOF"
📡 Daten-Quellen:
Wetter-APIs:
- OpenWeatherMap (free tier)
- Weatherstack
- NOAA (US Government)
Mond-Phasen:
- Python: ephem / skyfield
- Berechnung: Lunation Cycle (29.5 Tage)
Ideale Regenbogen-Bedingungen:
- Nach Regen ☔
- Sonne scheint ☀️
- Nachmittags (tieferer Sonnenstand)
- Luftfeuchtigkeit > 60%
- Vollmond Nacht? (Mondregenbogen!)
EOF
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "🕷️ Spider: API Integration"
spider "Ich spüre die Daten-Verbindungen: Wetter-API mit requests, Mond-Berechnung mit ephem. Wie oft pollen wir? Stündlich? Alle 10 Minuten?"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "🐘 DumboSQL: Historische Daten"
dumbosql "Ich erinnere mich an alle Regenbogen-Sichtungen. Mit historischen Daten können wir Muster erkennen: Wann erscheinen Regenbogen hier am häufigsten?"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# === PHASE 6: DER VORHERSAGE-ALGORITHMUS ===
read -p "🔮 Drücke Enter für Vorhersage..." -r
clear
echo "🔮 VORHERSAGE-ALGORITHMUS"
echo ""
cat << "EOF"
🧠 Machine Learning Light:
1. Feature Engineering:
- Mondphase (0-1)
- Wetter-Score (Regen + Sonne)
- Tageszeit (14-18 Uhr = hoch)
- Jahreszeit (Frühling/Herbst = hoch)
- Luftfeuchtigkeit
2. Scoring-System:
Score = moon_weight * moon_phase
+ weather_weight * weather_score
+ time_weight * time_score
+ humidity_weight * humidity
3. Threshold:
Score > 0.7 → "🌈 Hohe Wahrscheinlichkeit!"
Score 0.4-0.7 → "🤔 Möglich"
Score < 0.4 → "❌ Unwahrscheinlich"
EOF
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "🧭 Vektor: Zeit & Ort"
vektor "Navigation durch Zeit und Raum: Dein Standort bestimmt den Sonnenwinkel. Deine Zeitzone die Regenzeit. Wo bist du? Wann ist hier Regenbogen-Saison?"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "🦀 CrabbyRust: Sichere Daten"
crabbyrust "Wetter-Daten von extern, Kamera-Bilder lokal - wie halten wir das sicher? Validierung, Error-Handling, keine Race Conditions bei Multi-Threading?"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# === PHASE 7: VISUALISIERUNG ===
read -p "🎨 Drücke Enter für Visualisierung..." -r
clear
echo "🎨 VISUALISIERUNG & UI"
echo ""
echo "👾 ASCII-Monster malt den Mond..."
asciimonster "Erstelle ASCII-Art für Mond-Phasen: Neumond 🌑, Zunehmend 🌒🌓🌔, Vollmond 🌕, Abnehmend 🌖🌗🌘. Für das Terminal!"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
read -p "📊 Willst du ein Web-Dashboard? (j/n) " WANT_DASHBOARD
if [[ "$WANT_DASHBOARD" == "j" ]]; then
echo ""
echo "🧓 PepperPHP: Dashboard-Rezept"
pepperphp "Ein Dashboard mit: Live-Kamera-Feed, Mond-Phase-Anzeige, Wetter-Daten, Vorhersage-Score, Historische Sichtungen. Wie backen wir das mit Flask/FastAPI?"
echo ""
fi
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# === PHASE 8: DER MONDREGENBOGEN ===
read -p "🌙 Drücke Enter für das Finale..." -r
clear
echo "🦉 Maya-Eule: Die Legende vom Mondregenbogen"
echo ""
cat << "EOF"
🌙🌈 MONDREGENBOGEN (Lunar Rainbow)
Wusstest du?
Bei Vollmond kann es nachts Regenbogen geben!
Bedingungen:
- Vollmond 🌕
- Nach Regen (Wassertropfen in Luft)
- Dunkle Nacht
- Mond tief am Horizont (ca. 42° Winkel)
Die Mond Maschine könnte auch DAS vorhersagen!
Mondregenbogen sind selten und magisch. 🌙✨
Orte mit häufigen Mondregenbogen:
- Wasserfälle (z.B. Yosemite, Victoria Falls)
- Küsten nach Sturm
- Gebirge mit Nebel
EOF
echo ""
mayaeule "Die Mond Maschine verbindet Wissenschaft und Poesie. Vorhersagen heißt verstehen - und verstehen heißt staunen."
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# === ABSCHLUSS ===
read -p "🎓 Drücke Enter für Abschluss..." -r
clear
cat << "EOF"
🌙🎓 MOND MASCHINE: GEPLANT! 🎓🌙
Du hast gelernt:
📸 Computer Vision: OpenCV & Bildverarbeitung
🌦️ API Integration: Wetter & Astronomie-Daten
🧠 Machine Learning: Feature Engineering & Scoring
🌙 Astronomie: Mond-Phasen & Sonnenwinkel
🔮 Vorhersage: Algorithmen & Threshold-Systeme
📊 Visualisierung: Dashboard & Terminal-Art
🔐 Data Safety: Validierung & Error-Handling
"Vorhersagen heißt verstehen"
Mit dieser Mond Maschine kannst du die Natur
durch Code begreifen! 🌈✨
EOF
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# === LOG ===
LOGDIR="${CRUMB_LOGS_DIR:-$HOME/.crumbrobots_logs}/missions"
mkdir -p "$LOGDIR"
TIMESTAMP=$(date -Iseconds)
cat > "$LOGDIR/mond_maschine_${TIMESTAMP}.json" << EOF
{
"mission": "mond_maschine",
"timestamp": "$TIMESTAMP",
"vision": "$USER_VISION",
"camera": "$CAMERA_TYPE",
"wants_dashboard": "$WANT_DASHBOARD",
"crew_used": [
"mayaeule",
"dumbosql",
"funkfox",
"taichitaube",
"tobi",
"schnecki",
"schraubaer",
"snakepy",
"pepperphp",
"spider",
"crabbyrust",
"vektor",
"asciimonster"
],
"status": "planned",
"learning_areas": [
"computer_vision",
"opencv",
"weather_api",
"moon_phases",
"machine_learning",
"prediction_algorithms"
]
}
EOF
echo "📊 Mission geloggt: $LOGDIR/mond_maschine_${TIMESTAMP}.json"
echo ""
cat << "EOF"
📚 Nächste Schritte:
1. 🐍 Python Setup:
pip install opencv-python numpy requests ephem
2. 🌦️ Wetter-API Key besorgen:
- OpenWeatherMap: openweathermap.org/api
- Kostenloser Account
3. 📸 Kamera testen:
- OpenCV: cv2.VideoCapture(0)
- Testbild aufnehmen
4. 🌙 Mond-Phase berechnen:
import ephem
moon = ephem.Moon()
5. 🧠 Vorhersage-Algorithmus implementieren:
- Features sammeln
- Score berechnen
- Threshold setzen
6. 📊 Dashboard bauen (optional):
- Flask/FastAPI Backend
- Live-Updates mit WebSocket
7. 🌈 Warten auf den ersten Regenbogen!
EOF
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "🦉 Maya-Eule sagt:"
echo ""
echo " Die schönsten Maschinen sind die,"
echo " die uns die Wunder der Natur zeigen."
echo " 🌙🌈✨"
echo ""
read -p "🚀 Willst du jetzt bauen? (j/n) " BUILD_NOW
if [[ "$BUILD_NOW" == "j" ]]; then
echo ""
echo "🎉 FANTASTISCH! Die Crew ist bereit!"
echo ""
echo "🌙 Die Mond Maschine nimmt Form an..."
echo "💚 Viel Erfolg beim Bauen!"
else
echo ""
echo "💚 Kein Problem! Die Planung ist gespeichert."
echo "Die Mond Maschine wartet auf dich! 🌙✨"
fi
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "🌲 Zurück zum Wald..."
sleep 2

View File

@@ -1,52 +0,0 @@
from flask import Flask, render_template, Response, request, redirect
import cv2
import json
from datetime import datetime
app = Flask(__name__)
def gen_frames():
cam = cv2.VideoCapture(0)
if not cam.isOpened():
print("[WARNUNG] Kamera konnte nicht geöffnet werden.")
return
try:
while True:
success, frame = cam.read()
if not success:
break
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
finally:
cam.release()
print("[info] Kamera wurde sauber freigegeben.")
@app.route('/')
def index():
return render_template('index.html')
@app.route('/video_feed')
def video_feed():
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/log_answer', methods=['POST'])
def log_answer():
user_input = request.form.get('antwort', 'nichts gesagt')
mood = request.form.get('mood', 'unspecified')
gesture = request.form.get('gesture', 'none')
timestamp = datetime.now().isoformat()
log_entry = {
'timestamp': timestamp,
'antwort': user_input,
'mood': mood,
'gesture': gesture
}
with open("snake_log.jsonl", "a") as log_file:
log_file.write(json.dumps(log_entry) + "\n")
return redirect("/")

View File

@@ -1,13 +0,0 @@
import cv2
def gen_frames():
cap = cv2.VideoCapture(0)
while True:
success, frame = cap.read()
if not success:
break
else:
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')

View File

@@ -1,3 +0,0 @@
#!/bin/bash
echo "🐍 Starte SnakeCam ..."
exec python3 app.py

View File

@@ -1,15 +0,0 @@
# snakecam_module.py
import cv2
def init_camera(index=0):
cam = cv2.VideoCapture(index)
if not cam.isOpened():
print("[WARNUNG] Kamera konnte nicht geöffnet werden.")
return None
print("[OK] Kamera erfolgreich geöffnet.")
return cam
def release_camera(cam):
if cam and cam.isOpened():
cam.release()
print("[INFO] Kamera wurde freigegeben.")

View File

@@ -1,9 +0,0 @@
body {
background-color: #f0fff0;
font-family: 'Comic Sans MS', cursive, sans-serif;
text-align: center;
color: #006400;
}
h1 {
margin-top: 20px;
}

View File

@@ -1,80 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>🐍 SnakeCam Krümelblick ins Versteck</title>
<style>
body {
font-family: 'Comic Sans MS', sans-serif;
background-color: #e9f5e9;
color: #333;
text-align: center;
padding: 2rem;
}
img {
border: 4px dashed #4caf50;
border-radius: 12px;
max-width: 100%;
height: auto;
}
form {
margin-top: 2rem;
}
input, select {
padding: 0.5rem;
font-size: 1rem;
margin: 0.5rem;
border-radius: 6px;
border: 1px solid #ccc;
}
button {
padding: 0.7rem 1.2rem;
font-size: 1rem;
background-color: #4caf50;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
}
button:hover {
background-color: #388e3c;
}
</style>
</head>
<body>
<h1>🐍 SnakeCam</h1>
<p>Willkommen kleiner Krümel! Hier siehst du, was deine Kamera entdeckt.</p>
<!-- Live-Stream -->
<img src="/video_feed" alt="Live-Übertragung von SnakeCam 🐍" />
<!-- Eingabeformular -->
<form action="/log_answer" method="POST">
<p><strong>Was fühlst du gerade?</strong></p>
<input type="text" name="antwort" placeholder="Ich sehe einen ... 🐞🌳🤖" required>
<p><strong>Wie ist deine Stimmung?</strong></p>
<select name="mood">
<option value="happy">😊 Glücklich</option>
<option value="curious">🤔 Neugierig</option>
<option value="calm">😌 Ruhig</option>
<option value="excited">😃 Aufgeregt</option>
<option value="unspecified">🤷 Keine Angabe</option>
</select>
<p><strong>Hast du eine Geste gemacht?</strong></p>
<select name="gesture">
<option value="none">🚫 Keine</option>
<option value="wave">👋 Winken</option>
<option value="thumbs_up">👍 Daumen hoch</option>
<option value="peace">✌️ Peace</option>
<option value="other">✨ Etwas anderes</option>
</select>
<br><br>
<button type="submit">🎯 Eintragen</button>
</form>
</body>
</html>

View File

@@ -1,73 +0,0 @@
# -*- coding: utf-8 -*-
from flask import Flask, render_template, Response, request, redirect, url_for
import cv2
import json
from datetime import datetime
from gestures.gestures_debug_test import detect_hand_gesture
app = Flask(__name__)
# Kamera initialisieren
cam = cv2.VideoCapture(0)
cam.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
def gen_frames():
while True:
success, frame = cam.read()
if not success:
print("[error] Kein Kamerabild.")
break
# Optional spiegeln (für Selfie-Effekt)
frame = cv2.flip(frame, 1)
# Geste erkennen + ROI anzeigen
gesture, roi_coords = detect_hand_gesture(frame)
x, y, w, h = roi_coords
# Rechteck einzeichnen
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.putText(frame, f"Geste: {gesture}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
# MJPEG-Streaming
ret, buffer = cv2.imencode('.jpg', frame)
frame_bytes = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n')
@app.route('/')
def index():
return render_template('index.html')
@app.route('/video_feed')
def video_feed():
return Response(gen_frames(),
mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/log_answer', methods=['POST'])
def log_answer():
answer = request.form.get("antwort", "").strip()
mood = request.form.get("mood", "neutral")
gesture = request.form.get("gesture", "none")
log_entry = {
"timestamp": datetime.now().isoformat(),
"antwort": answer,
"mood": mood,
"gesture": gesture
}
with open("snake_log.jsonl", "a") as logfile:
logfile.write(json.dumps(log_entry) + "\n")
print(f"[log] Eingeloggt: {log_entry}")
return redirect(url_for('index'))
@app.route('/shutdown')
def shutdown():
cam.release()
print("[info] Kamera wurde sauber freigegeben.")
return "Kamera freigegeben."
if __name__ == '__main__':
print("Starte SnakeCam ...")
app.run(host='0.0.0.0')

View File

@@ -1,59 +0,0 @@
print("[SnakeCam] Initialisierung beginnt...")
from flask import Flask, render_template, Response, request, redirect
import cv2
import json
from datetime import datetime
print("[SnakeCam] Imports erfolgreich.")
app = Flask(__name__)
def gen_frames():
cam = cv2.VideoCapture(0)
if not cam.isOpened():
print("[WARNUNG] Kamera konnte nicht geöffnet werden.")
return
try:
while True:
success, frame = cam.read()
if not success:
break
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
finally:
cam.release()
print("[info] Kamera wurde sauber freigegeben.")
@app.route('/')
def index():
return render_template('index.html')
@app.route('/video_feed')
def video_feed():
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/log_answer', methods=['POST'])
def log_answer():
user_input = request.form.get('antwort', 'nichts gesagt')
mood = request.form.get('mood', 'unspecified')
gesture = request.form.get('gesture', 'none')
timestamp = datetime.now().isoformat()
log_entry = {
'timestamp': timestamp,
'antwort': user_input,
'mood': mood,
'gesture': gesture
}
with open("snake_log.jsonl", "a") as log_file:
log_file.write(json.dumps(log_entry) + "\n")
return redirect("/")
if __name__ == "__main__":
print("[SnakeCam] Starte Flask Webserver ...")
app.run(host='0.0.0.0', port=5000)

View File

@@ -1,72 +0,0 @@
from flask import Flask, render_template, Response, request, redirect
import cv2
import datetime
import json
from gestures_debug import detect_hand_gesture
app = Flask(__name__)
def gen_frames():
cam = cv2.VideoCapture(0)
cam.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
if not cam.isOpened():
print("[WARNUNG] Kamera konnte nicht geöffnet werden.")
return
try:
while True:
success, frame = cam.read()
if not success:
break
# Flip horizontal für Spiegelbild
frame = cv2.flip(frame, 1)
# Geste erkennen
gesture, roi = detect_hand_gesture(frame)
if isinstance(roi, tuple) and len(roi) == 4:
x, y, w, h = roi
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.putText(frame, gesture, (x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
# Frame in JPEG konvertieren
ret, buffer = cv2.imencode('.jpg', frame)
frame_bytes = buffer.tobytes()
# MJPEG-Stream liefern
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n')
finally:
cam.release()
print("[info] Kamera wurde sauber freigegeben.")
@app.route('/')
def index():
return render_template('index.html')
@app.route('/video_feed')
def video_feed():
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/log_answer', methods=['POST'])
def log_answer():
data = {
"timestamp": datetime.datetime.now().isoformat(),
"antwort": request.form.get("antwort", ""),
"mood": request.form.get("mood", ""),
"gesture": request.form.get("gesture", "")
}
with open("snake_log.jsonl", "a") as f:
f.write(json.dumps(data) + "\n")
return redirect("/")
if __name__ == '__main__':
print("[SnakeCam] Initialisierung beginnt...")
print("[SnakeCam] Imports erfolgreich.")
print("[SnakeCam] Starte Flask Webserver ...")
app.run(host='0.0.0.0', port=5000)

View File

@@ -1,77 +0,0 @@
# gestures_v3.py
import cv2
import numpy as np
from datetime import datetime
# Pfad zum temporären Snapshot zur Diagnose
DEBUG_SNAPSHOT_PATH = "/tmp/roi_snapshot.jpg"
def detect_hand_gesture(frame):
"""
Erkenne einfache Handgesten wie 'wave' (offene Hand) und 'fist' (geschlossene Faust)
durch Analyse der Konturen im unteren rechten Bildbereich.
Die Erkennung basiert auf konvexer Hüllenerkennung.
Args:
frame (ndarray): Das aktuelle Kamerabild
Returns:
(str, ndarray): (Geste, Region-of-Interest-Ausschnitt)
"""
height, width, _ = frame.shape
# ROI: untere rechte Ecke (¼ des Bildes)
roi = frame[int(height * 0.6):height, int(width * 0.6):width]
# Speichere Snapshot für Debug-Zwecke
cv2.imwrite(DEBUG_SNAPSHOT_PATH, roi)
# Konvertiere zu HSV
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
# Hautfarbmaske (angepasst für unterschiedliche Beleuchtung)
lower_skin = np.array([0, 30, 60], dtype=np.uint8)
upper_skin = np.array([20, 150, 255], dtype=np.uint8)
mask = cv2.inRange(hsv, lower_skin, upper_skin)
# Glätten und Konturen erkennen
mask = cv2.GaussianBlur(mask, (7, 7), 0)
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
if contours and len(contours) > 0:
# Größte Kontur (Handfläche)
contour = max(contours, key=cv2.contourArea)
# Fehler vermeiden: Fläche zu klein
if cv2.contourArea(contour) < 1000:
return ("none", roi)
# Konvexe Hülle und Defekte
hull = cv2.convexHull(contour, returnPoints=False)
if hull is not None and len(hull) > 3:
defects = cv2.convexityDefects(contour, hull)
if defects is not None:
finger_count = 0
for i in range(defects.shape[0]):
s, e, f, d = defects[i, 0]
start = tuple(contour[s][0])
end = tuple(contour[e][0])
far = tuple(contour[f][0])
# Abstand analysieren je mehr Defekte, desto mehr Finger offen
a = np.linalg.norm(np.array(start) - np.array(end))
b = np.linalg.norm(np.array(start) - np.array(far))
c = np.linalg.norm(np.array(end) - np.array(far))
angle = np.arccos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c + 1e-5))
if angle <= np.pi / 2: # < 90°
finger_count += 1
# Auswertung basierend auf Fingeranzahl
if finger_count >= 3:
return ("wave", roi)
elif finger_count == 0:
return ("fist", roi)
return ("none", roi)

View File

@@ -1,35 +0,0 @@
import cv2
import numpy as np
# --- Handgestenerkennung: Einfacher Hautfarbfilter + Konturanalyse ---
def detect_hand_gesture(frame):
# Region of Interest (z.B. linke obere Ecke) definieren
roi = frame[20:120, 20:120]
# Konvertiere in HSV-Farbraum
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
# Hautfarb-Bereich (kann je nach Licht angepasst werden)
lower_skin = np.array([0, 30, 60], dtype=np.uint8)
upper_skin = np.array([20, 150, 255], dtype=np.uint8)
# Maske für Hautfarbe erzeugen
mask = cv2.inRange(hsv, lower_skin, upper_skin)
# Konturen finden
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
gesture = "none"
# Wenn große Kontur gefunden → einfache „Winken“-Simulation
if contours:
largest_contour = max(contours, key=cv2.contourArea)
if cv2.contourArea(largest_contour) > 1000:
gesture = "wave"
# ROI im Hauptframe markieren
cv2.rectangle(frame, (20, 20), (120, 120), (0, 255, 0), 2)
cv2.putText(frame, f"Gesture: {gesture}", (20, 160),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
return gesture, frame

View File

@@ -1,50 +0,0 @@
import cv2
import numpy as np
def detect_hand_gesture(frame):
height, width, _ = frame.shape
# Dynamische ROI: Mitte des Bildes, zentriert
roi_w, roi_h = 200, 200
x_start = width // 2 - roi_w // 2
y_start = height // 2 - roi_h // 2
roi = frame[y_start:y_start + roi_h, x_start:x_start + roi_w]
# Zeichne das ROI-Fenster im Originalbild
cv2.rectangle(frame, (x_start, y_start), (x_start + roi_w, y_start + roi_h), (0, 255, 0), 2)
# Konvertiere zu HSV-Farbraum für bessere Hauterkennung
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
# Hautfarbmaske (getestet für mittlere Hauttöne)
lower_skin = np.array([0, 30, 60], dtype=np.uint8)
upper_skin = np.array([20, 150, 255], dtype=np.uint8)
mask = cv2.inRange(hsv, lower_skin, upper_skin)
# Glättung und Konturen finden
mask = cv2.GaussianBlur(mask, (5, 5), 0)
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
if contours:
# Größte Kontur annehmen
max_contour = max(contours, key=cv2.contourArea)
area = cv2.contourArea(max_contour)
if area > 2000:
# Konvexitätsdefekte (Finger) berechnen
hull = cv2.convexHull(max_contour, returnPoints=False)
if hull is not None and len(hull) > 3:
defects = cv2.convexityDefects(max_contour, hull)
finger_count = 0
if defects is not None:
for i in range(defects.shape[0]):
s, e, f, d = defects[i, 0]
if d > 10000:
finger_count += 1
if finger_count >= 3:
return "wave", roi
else:
return "fist", roi
return "none", roi

View File

@@ -1,50 +0,0 @@
# gestures_debug.py
import cv2
import numpy as np
def detect_hand_gesture(frame):
height, width, _ = frame.shape
# --- Fallback-ROI: Mitte des Bildes ---
w, h = 100, 100
x = width // 2 - w // 2
y = height // 2 - h // 2
roi = frame[y:y+h, x:x+w]
if roi.size == 0:
print("[warn] ROI leer kein Bildausschnitt verarbeitet")
return "none", (x, y, w, h)
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
lower_skin = np.array([0, 20, 70], dtype=np.uint8)
upper_skin = np.array([20, 255, 255], dtype=np.uint8)
mask = cv2.inRange(hsv, lower_skin, upper_skin)
mask = cv2.dilate(mask, np.ones((3, 3), np.uint8), iterations=4)
mask = cv2.GaussianBlur(mask, (5, 5), 100)
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
gesture = "none"
if contours and len(contours) > 0:
max_contour = max(contours, key=cv2.contourArea)
hull = cv2.convexHull(max_contour, returnPoints=False)
if hull is not None and len(hull) > 3:
defects = cv2.convexityDefects(max_contour, hull)
if defects is not None:
cnt_defects = defects.shape[0]
if cnt_defects >= 4:
gesture = "wave"
elif cnt_defects <= 1:
gesture = "fist"
else:
gesture = "unknown"
print(f"[debug] Defekte: {len(defects) if defects is not None else 'None'}")
else:
print("[debug] Keine Konturen erkannt")
print(f"[result] Geste erkannt: {gesture}")
return gesture, (x, y, w, h)

View File

@@ -1,29 +0,0 @@
import cv2
import numpy as np
def detect_hand_gesture(frame):
x, y, w, h = 100, 100, 200, 150
roi = frame[y:y+h, x:x+w]
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
# Hautfarbe grob einschränken
lower_skin = np.array([0, 30, 60], dtype=np.uint8)
upper_skin = np.array([20, 150, 255], dtype=np.uint8)
mask = cv2.inRange(hsv, lower_skin, upper_skin)
mask = cv2.GaussianBlur(mask, (5, 5), 0)
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
gesture = "none"
if contours:
contour = max(contours, key=cv2.contourArea)
area = cv2.contourArea(contour)
if area > 3000:
print(f"[debug] Fläche erkannt: {int(area)}")
gesture = "hand"
return gesture, (x, y, w, h)

View File

@@ -1,39 +0,0 @@
import cv2
import numpy as np
def detect_hand_gesture(frame):
x, y, w, h = 100, 100, 150, 150
roi = frame[y:y+h, x:x+w]
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
# einfache Hautfarbe (hell bis leicht gebräunt)
lower_skin = np.array([0, 30, 60], dtype=np.uint8)
upper_skin = np.array([20, 150, 255], dtype=np.uint8)
mask = cv2.inRange(hsv, lower_skin, upper_skin)
mask = cv2.GaussianBlur(mask, (5, 5), 0)
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
gesture = "none"
if contours:
contour = max(contours, key=cv2.contourArea)
area = cv2.contourArea(contour)
if area > 2500:
hull = cv2.convexHull(contour, returnPoints=False)
if hull is not None and len(hull) > 3:
defects = cv2.convexityDefects(contour, hull)
if defects is not None:
defect_count = defects.shape[0]
ratio = float(w) / h
print(f"[debug] Defekte: {defect_count}, Fläche: {int(area)}, Ratio: {ratio:.2f}")
# 🌊 einfache Regel für Winken
if 3 <= defect_count <= 10 and 2000 < area < 15000 and 1.3 < ratio < 2.3:
gesture = "wave"
return gesture, (x, y, w, h)

View File

@@ -1,3 +0,0 @@
#!/bin/bash
echo "🐍 Starte SnakeCam ..."
python3 app.py

View File

@@ -1,62 +0,0 @@
body {
font-family: Arial, sans-serif;
background-color: #111;
color: #eee;
text-align: center;
padding: 20px;
}
h1 {
margin-bottom: 20px;
color: #90ee90;
}
.video-container {
margin-bottom: 20px;
}
img {
width: 320px;
height: auto;
border: 2px solid #555;
border-radius: 8px;
}
img.mirrored {
/* transform: scaleX(-1); Spiegelung horizontal */
transform: none;
}
form {
display: inline-block;
text-align: left;
background: #222;
padding: 15px;
border-radius: 10px;
}
label, select, input, button {
display: block;
width: 100%;
margin-bottom: 10px;
}
input, select {
padding: 6px;
border-radius: 4px;
border: none;
}
button {
background-color: #28a745;
color: white;
font-weight: bold;
cursor: pointer;
border: none;
padding: 10px;
border-radius: 5px;
}
button:hover {
background-color: #218838;
}

View File

@@ -1,115 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>🐍 SnakeCam Vision</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #111;
color: #eee;
text-align: center;
padding: 20px;
}
h1 {
margin-bottom: 20px;
color: #90ee90;
}
.video-container {
display: inline-block;
border: 4px solid #333;
background: black;
}
img {
width: 320px;
height: 240px;
object-fit: cover;
}
.video-container {
margin-bottom: 20px;
}
form {
display: inline-block;
text-align: left;
background: #222;
padding: 15px;
border-radius: 10px;
}
label, select, input, button {
display: block;
width: 100%;
margin-bottom: 10px;
}
input, select {
padding: 6px;
border-radius: 4px;
border: none;
}
button {
background-color: #28a745;
color: white;
font-weight: bold;
cursor: pointer;
border: none;
padding: 10px;
border-radius: 5px;
}
button:hover {
background-color: #218838;
}
</style>
</head>
<body>
<h1>🐍 SnakeCam Vision</h1>
<div class="video-container">
<img src="{{ url_for('video_feed') }}" alt="Live Video Feed">
</div>
<br clear=all/>
<form id="logForm">
<p>
<label for="antwort">Antwort:</label><br>
<input type="text" id="antwort" name="antwort" placeholder="Was denkst du?">
</p>
<p>
<label for="mood">Stimmung:</label><br>
<select id="mood" name="mood">
<option value="happy">😄 Happy</option>
<option value="excited">🤩 Excited</option>
<option value="neutral">😐 Neutral</option>
<option value="confused">😕 Confused</option>
</select>
</p>
<p>
<label for="gesture">Geste:</label><br>
<select id="gesture" name="gesture">
<option value="wave">👋 Wave</option>
<option value="fist">✊ Faust</option>
<option value="none">🚫 Keine</option>
</select>
</p>
<button type="submit">📝 Speichern</button>
</form>
<script>
document.getElementById("logForm").addEventListener("submit", async function(e) {
e.preventDefault(); // Kein Reload!
const formData = new FormData(this);
await fetch("/log_answer", {
method: "POST",
body: formData
});
console.log("✅ Antwort wurde gespeichert.");
this.reset(); // Eingabefelder leeren
});
</script>
</body>
</html>

View File

@@ -1,4 +0,0 @@