Hier gibt es Informationen zu meinen Projekten
Informatikstudent
Responsive Website mit HTML, CSS, JavaScript, PHP & SEO.
Spielekonsole mit ATmega168 programmiert in C.
Kreuzworträtsel in HTML mit externer Wortliste.
Onlinepokerspiel mit Dedicated Server.
Sprechender Partikelkopf mit Texttransformation für KI-Chatbot.
Fahrender KI Bot.
Benchmark für KI Chatbot.
Spielentwicklung in UE5 & C++.
Einrichtung, Hardening & Wartung unter Ubuntu.
Fokus auf zugängliches UI und Performance. Die Oberfläche setzt auf semantisches HTML5, modernes CSS (Flexbox/Grid) und Vanilla JavaScript ohne schwere Frameworks.
Serverseitige Aspekte (z. B. HTTPS/Hardening, Admin-API) dokumentiere ich getrennt im Projekt „Ubuntu vServer“.
Framework-freies Frontend mit klarer Schichtentrennung: HTML (Struktur), CSS (Layout), JavaScript (Interaktion).
Chat-UI mit Eingabe und Verlauf. Anfragen per Fetch an chat_proxy.php → lokales LLM (Ollama, qwen2:0.5b).
Keine externen APIs, volle Kontrolle
Formular mit Google reCAPTCHA gesichert gegen Spam, Token-Nutzung. Formular aktuell deaktiviert („nicht verfügbar“-Overlay).
aria-labels & alt-Texte für Bilder.sitemap.xml & robots.txt vorhanden.defer-Scripts, moderne CSS-Techniken.alt-Texten für Suche & Barrierefreiheit.
Im Uniprojekt Mikroelektronik (IMS, Leibniz Universität Hannover) habe ich eine kleine Mikrocontroller-basierte Spielekonsole im Stil Do-It-Yourself-PacMan umgesetzt. Das Projekt war bewusst als vollständiger Hardware-&-Software-Durchlauf aufgebaut und bestand aus drei klar getrennten Phasen: zuerst PCB-Layout, dann Bestückung & Löten, und erst danach Programmierung (C/AVR-GCC) für Grafik, Eingabe und Spielmechanik.
Ziel war es, Embedded-Entwicklung nicht nur softwareseitig zu betrachten, sondern den kompletten Weg von der Hardwareerstellung bis zur laufenden Anwendung zu beherrschen. Neben der Mikrocontroller-Programmierung standen insbesondere Schaltung/Platinenrealisierung, sauberes Löten sowie das Verständnis von Signalverarbeitung und Timing (VGA) im Vordergrund.
In der ersten Phase wurde die Platine entworfen. Dabei ging es nicht um „nur irgendein Layout“, sondern um eine funktionale, fertigungstaugliche Umsetzung, bei der elektrische Anforderungen und praktische Bestückbarkeit berücksichtigt werden müssen.
In der zweiten Phase wurde das fertige PCB praktisch aufgebaut: elektrische Bauteile wurden bestückt und verlötet, anschließend wurde auch der ATmega168 auf der Platine verlötet. Damit war die Hardwarebasis für die spätere Programmierung und die Signaltests geschaffen.
Erst nachdem die Hardware fertig aufgebaut war, wurde der Controller programmiert. Hier ging es um die Implementierung der Plattformfunktionen (I/O, Timing, Grafik), und darauf aufbauend um eine kleine Spielelogik. Der Code läuft ohne Betriebssystem und muss deterministisch mit den Anforderungen der Ausgabesignale umgehen.
.hex → Flashen.Um mit stark begrenztem Speicher dennoch eine „spielartige“ Darstellung zu ermöglichen, wurde ein Tile-/Sprite-Konzept eingesetzt. Der Hintergrund wird aus wiederverwendbaren Tiles aufgebaut; bewegte Objekte werden als Sprites darüber gezeichnet. Ein Overlay dient für UI-Elemente (z. B. Punktestand).
Die Steuerung erfolgt über digitale Eingänge, die den Gamepad-Richtungen zugeordnet sind. Zusätzlich werden LEDs zur Rückmeldung genutzt. Die feste Pinbelegung erlaubt klare, nachvollziehbare Zuordnungen zwischen Hardware und Code.
Als praxisnahes Ziel wurde Pong umgesetzt bzw. als Aufgabenblock realisiert: zwei Spieler, bewegliche Schläger, Ballbewegung, Kollisionen und Punktezählung. Damit lässt sich die gesamte Kette aus Eingabe → Logik → Grafik/Timing zuverlässig testen.
Dieses Projekt verbindet Python-basierte Datenaufbereitung mit einer interaktiven HTML/JavaScript-Anwendung. Ziel war es, eine große, qualitativ geeignete Wortbasis aus Wiktionary zu extrahieren, automatisiert zu filtern und in ein Format zu überführen, das direkt von einem browserbasierten Kreuzworträtsel genutzt werden kann.
Kernanforderung war eine skalierbare Wortliste mit ca. 20.000 Einträgen, bestehend aus Lösungswort, Hinweis und Schwierigkeitsgrad, angepasst an die technischen Randbedingungen des Rasters (maximale Wortlänge, Großbuchstaben, ASCII-kompatibel).
Ziel war es, ein Kreuzworträtsel nicht nur mit einer kleinen, statischen Wortliste auszustatten, sondern eine beliebig erweiterbare, automatisch generierte Wortdatenbank zu schaffen. Die Wortliste sollte sprachlich sauber, rätseltauglich und technisch exakt auf das Frontend abgestimmt sein.
Das Python-Skript bildet das Rückgrat des Projekts. Es verarbeitet eine sehr große Wiktionary-Extraktdatei im JSONL-Format zeilenweise und erzeugt daraus eine optimierte, browserfreundliche JavaScript-Wortliste.
Damit die Wörter direkt in einem festen Kreuzwortraster verwendbar sind, erfolgt eine konsequente Normalisierung:
Die Hinweise stammen aus den Bedeutungsangaben (Glosses) von Wiktionary und werden gezielt bereinigt, um sie für Kreuzworträtsel nutzbar zu machen.
Jedes Wort wird automatisch einem Schwierigkeitsgrad zugeordnet, basierend auf der Wortlänge. Diese Information wird im Frontend genutzt, um Rätsel zu steuern oder später adaptive Schwierigkeitsstufen zu ermöglichen.
Das Ergebnis des Skripts ist keine rohe Datendatei, sondern eine direkt einbindbare JavaScript-Datei. Diese erweitert zur Laufzeit das globale Wortarray des Kreuzworträtsels.
{ ans, clue, diff }.<script> einbindbar.Das Frontend ist ein vollständig eigenständiges Kreuzworträtsel, das die erzeugte Wortliste dynamisch nutzt. Das Raster, die Hinweise und die Interaktion sind komplett im Browser umgesetzt.
Java-Netzwerkprojekt: Entwicklung eines vollständigen Texas-Hold’em-Pokerspiels mit dediziertem Server und mehreren Clients im lokalen Netzwerk. Fokus des Projekts liegt auf korrekter Spiellogik, zuverlässiger Client-Server-Kommunikation und einer stabilen JavaFX-Benutzeroberfläche.
Ziel war es, ein echtes Multiplayer-Spiel zu entwickeln, das nicht nur technisch funktioniert, sondern auch inhaltlich korrektes Poker abbildet. Besonderer Fokus lag auf State-Management, Synchronisation und der sauberen Trennung von Netzwerk, Logik und UI.
Die komplette Hold’em-Logik ist serverseitig implementiert und strikt regelkonform:
Ein zentraler Teil des Projekts war das Polishing: das systematische Finden und Beheben von Spiellogik-Fehlern.
Dieses Projekt ist eine interaktive Partikelkopf-Animation, die als dynamischer, moderner Header-Hero bzw. als visuelles Element für einen KI-Chatbot eingesetzt werden kann. Die Demo rendert bewusst mit Canvas 2D (statt WebGL/Three.js), um eine sehr direkte Kontrolle über Performance, Buffer-Reuse und Rendering-Pipeline zu haben.
Ergebnis: Ein leichtgewichtiges Creative-Coding-Modul, das trotz hoher Partikelzahlen (mehrere Tausend) stabil läuft und sich über UI-Slider fein an Hardware, Layout und gewünschte Ästhetik anpassen lässt.
Die Demo protokolliert dabei u. a. die erkannten Gruppen (Debug/Console) und nutzt diese als Basis für die Sprech-Komposition. :contentReference[oaicite:2]{index=2}
prefers-reduced-motion werden konservativere Punktzahlen gesetzt.visibilitychange) und wenn Canvas off-screen ist (IntersectionObserver).Diese Kombination sorgt dafür, dass die Demo auch als dauerhaft laufendes Header-Element stabil bleibt, ohne unnötig CPU/GPU zu “verheizen”. :contentReference[oaicite:3]{index=3}
aria-label; UI als klare, kompakte “Pill”-Controls.
In diesem Projekt entsteht schrittweise ein stationärer KI-Bot auf Arduino UNO-Basis (Elegoo-Kit) – mit Fokus auf sauberem Hardware-Grundaufbau, robusten Tests und einem klaren Ausbaupfad. Das spätere Ziel ist ein fahrfähiger Bot, jedoch wird Fahren bewusst zuletzt umgesetzt (Räder/Chassis sind noch nicht vorhanden).
FQBN: arduino:avr:uno, Upload via avrdude auf COM3.Ziel ist ein stabiler, erweiterbarer Embedded-Prototyp, der später mit Sensorik, Aktoren und ggf. einem zusätzlichen Mikrocontroller (z. B. ESP32) erweitert werden kann. Der Start erfolgt bewusst mit Basis-Verifikation (Board/Port/Upload/I/O) und nicht mit “komplexer Mechanik”.
GND sauber verbunden sein (gemeinsamer Bezug).
Das Board wurde erfolgreich als UNO erkannt und programmiert (AVR-Core, Upload über avrdude).
Upload-Logs zeigen korrektes Target: ATmega328P und erfolgreiche Flash-Writes.
arduino:avr:unoCOM3avrdudeZur eindeutigen Sichtbarkeit wurde ein unregelmäßiges Blinkmuster genutzt statt Standard-Blink. Damit ist sicher: Upload läuft, Loop läuft, Timing/Delay funktioniert.
D13 gekoppelt.Der Servo wurde erfolgreich in Betrieb genommen. Der wichtigste Punkt dabei: Es gibt am UNO mehrere PWM-Pins, aber in diesem Aufbau wurde D9 (~9) als Signalpin genutzt.
D9 (PWM-Pin „~9“).5V des UNO (für den ersten Test ok).GND des UNO.Hinweis: Die Servo-Kabel lassen sich nicht immer sauber “auftrennen”. Im Projekt wurde daher ein mechanisch passender Steckweg gewählt. Kritisch ist nur, dass Signal/VCC/GND eindeutig korrekt sitzen.
Für den klassischen Servo-Test auf UNO ist in der Regel keine zusätzliche Elegoo-Library nötig,
da die Arduino-Standard-Servo-Library bereits vorhanden ist und kompiliert wurde.
Im Build-Log wurde Servo v1.3.0 verwendet.
Ein erfolgreicher Upload bedeutet nur: Flash wurde beschrieben. Sichtbares Verhalten hängt davon ab, ob der Sketch tatsächlich etwas Sichtbares tut (LED, Serial-Output, Servo-Bewegung). Ein Servo kann sich außerdem sehr kurz bewegen (Startposition), sodass man es ohne klaren Testablauf leicht verpasst. Im Projekt wurde das durch spätere eindeutige Tests (Blinkmuster/Servo-Bewegung) behoben.
D9 erfolgreich betrieben.Ein ESP32 kann das System sinnvoll erweitern (z. B. WLAN/BLE, schnellere Rechenleistung), aber ohne zusätzliches Zubehör ist der unmittelbare Nutzen vor allem in Kommunikation (z. B. Telemetrie/Remote-Control) und Software-Experimenten. Hardwareseitig bleibt der UNO für simple I/O-Aufgaben weiterhin gut geeignet.
Dieses Projekt ist ein leichtgewichtiges Python-Benchmark-Tool, das die
Zuverlässigkeit meines lokalen Website-Chatbots (Frontend → chat_proxy.php → Ollama) überprüft.
Fokus ist Robustheit unter mehreren Requests (seriell & parallel) – ohne schweres Debug-Framework,
ohne Cloud-APIs und ohne „Timeout hochdrehen“ als Scheinlösung.
127.0.0.1), inkl. Redirect-/TLS-Fallen.Ergebnis: Ein reproduzierbarer „Health-Check“, der schnell zeigt, ob der Bot im aktuellen Deployment unter realistischen Bedingungen zuverlässig bleibt.
Der Benchmark bewertet primär: Kommt jemals die Timeout-Fehlermeldung zurück? Geschwindigkeit wird zwar gemessen, ist aber nicht das Hauptkriterium – denn ein Bot kann „langsam aber stabil“ sein und ist dann zumindest korrekt betreibbar. Die Performance-Optimierung ist ein eigener Schritt.
In der Praxis sind Benchmarks oft „falsch negativ“, weil sie nicht denselben Pfad treffen wie das Frontend. Der Benchmark ist deshalb so aufgebaut, dass er genau die Web-Realität abprüft:
https://philippkahle.com/php/chat_proxy.phphttp://127.0.0.1/php/chat_proxy.php kann (je nach Nginx vHost)
ein 301 auf HTTPS liefern. Wenn dein Benchmark keine Redirects sauber behandelt, sieht das wie „kaputt“ aus.
https://127.0.0.1/... funktionieren oft nicht ohne korrektes SNI/Host-Handling
(und ggf. Zertifikats-Setup). Deshalb ist „Live-URL“ die robusteste Referenz.
http://127.0.0.1:11434/api/chat dient als Kontrollmessung (ohne PHP/Nginx).
Fehlerklasse invalid_json bedeutet meist nicht „Model kaputt“, sondern:
Der Server liefert HTML/Redirect oder eine unerwartete Response (z. B. 301-Seite), die nicht JSON ist.
Der Benchmark loggt daher zusätzlich: Statuscode, Content-Type und einen kurzen Response-Snippet bei Fehlern.
4/20), damit „hängt“ vs. „arbeitet“ unterscheidbar istTarget: https://philippkahle.com/php/chat_proxy.php
Serial=20, Parallel=40, Concurrency=4, Timeout=120s
=== Serial test (live) ===
4/20 OK=4 (100%) ERR=0 p50=1820ms p95=2710ms max=2955ms errors={}
=== Parallel test (live) ===
12/40 OK=12 (100%) ERR=0 p50=2450ms p95=6100ms max=8900ms errors={}
CPU-only LLMs skalieren bei jedem Turn in zwei Phasen, die im Timing sichtbar werden: Prompt-Eval (Kontext „lesen“) und Generation (Token „schreiben“). Wenn Website-Kontext und/oder History wachsen, wächst vor allem die Prompt-Eval-Last – und die ist bei CPU teuer. Der beobachtete „Dominoeffekt“ ist deshalb realistisch: jeder Turn macht den nächsten Turn teurer.
# 1) Projektordner
mkdir -p ~/chatbench
cd ~/chatbench
# 2) Virtuelle Umgebung
python3 -m venv venv
source venv/bin/activate
# 3) Dependencies (requests)
pip install requests
# 4) Run
python bench_chat.py
chat_proxy.php, einmal direkt via /api/chat (Isolierung von PHP/Nginx vs. Ollama).num_predict, num_ctx, ggf. keep_alive und Stop-Sequenzen – ohne UX zu zerstören.
Unreal Engine 5 Beispielprojekt: Umsetzung eines sichtbaren Schusses per Line Trace, sowohl mittels Blueprint als auch in C++. Ziel ist es, unabhängig von Spiellogik oder Gameplay-Mechaniken eine robuste Grundlage für Treffererkennung und Debug-Visualisierung zu schaffen.
OnFire() mit LineTraceSingleByChannel, Debug-Ausgabe und On-Screen-Meldungen.Visibility = Block haben, eigener Charakter wird ignoriert.Dieses Beispiel zeigt, wie man in UE5 mit Blueprints und C++ arbeitet, um Schussmechaniken technisch korrekt umzusetzen.
Eine nachvollziehbare, sofort sichtbare Schuss-Simulation: Beim Drücken der Fire-Taste feuert die Kamera einen Line Trace ab, der per Debug-Linie und -Sphäre visualisiert wird und den getroffenen Actor/Component als Text ausgibt.
Fire (z. B. linke Maustaste).InputAction Fire (Pressed).Start = FirstPersonCamera.GetWorldLocation()End = Start + FirstPersonCamera.GetForwardVector() * 15000.0 (Reichweite nach Bedarf).Visibility, Ignore Self aktivieren, optional Debug Type = For Duration.| Objekt | Einstellung |
|---|---|
| Treffbare Zielobjekte | Collision Enabled = Query Only, Response to Visibility = Block |
| Eigener Charakter | Ignore Self aktivieren, damit kein Treffer am eigenen Pawn ausgelöst wird |
Die gleiche Funktionalität in C++ implementiert: Line Trace von der Kamera, Debug-Visualisierung, On-Screen-Feedback.
YourCharacter.h#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Camera/CameraComponent.h"
#include "YourCharacter.generated.h"
UCLASS()
class YOURMODULE_API AYourCharacter : public ACharacter
{
GENERATED_BODY()
public:
AYourCharacter();
protected:
virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override;
UFUNCTION() void OnFire();
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
UCameraComponent* FirstPersonCamera = nullptr;
UPROPERTY(EditAnywhere, Category="Shooting")
float TraceRange = 15000.f;
UPROPERTY(EditAnywhere, Category="Shooting")
TEnumAsByte<ECollisionChannel> TraceChannel = ECC_Visibility;
};
YourCharacter.cpp#include "YourCharacter.h"
#include "DrawDebugHelpers.h"
#include "Engine/Engine.h"
AYourCharacter::AYourCharacter()
{
FirstPersonCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
FirstPersonCamera->SetupAttachment(GetCapsuleComponent());
FirstPersonCamera->bUsePawnControlRotation = true;
}
void AYourCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &AYourCharacter::OnFire);
}
void AYourCharacter::OnFire()
{
if (!FirstPersonCamera) return;
UWorld* World = GetWorld();
if (!World) return;
const FVector Start = FirstPersonCamera->GetComponentLocation();
const FVector End = Start + FirstPersonCamera->GetForwardVector() * TraceRange;
FHitResult Hit;
FCollisionQueryParams Params(SCENE_QUERY_STAT(ShootTrace), false);
Params.AddIgnoredActor(this);
const bool bHit = World->LineTraceSingleByChannel(Hit, Start, End, TraceChannel, Params);
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
DrawDebugLine(World, Start, End, FColor::Green, false, 1.0f, 0, 1.5f);
#endif
if (bHit)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
DrawDebugSphere(World, Hit.ImpactPoint, 10.f, 12, FColor::Cyan, false, 1.0f);
#endif
if (GEngine)
{
const FString Msg = FString::Printf(TEXT("Hit: %s / %s"),
*GetNameSafe(Hit.GetActor()), *GetNameSafe(Hit.Component.Get()));
GEngine->AddOnScreenDebugMessage(INDEX_NONE, 1.5f, FColor::Yellow, Msg);
}
}
}
Visibility bereits stark genutzt wird.
Ubuntu vServer als Basis der Website – eingerichtet, gehärtet und optimiert.
Ergebnis: stabiler, sicherer und modularer Server für produktive Websites.
Ubuntu 22.04 LTS, minimale Installation.
Domain philippkahle.com & www → vServer-IP.
Sitemap & robots.txt erstellt, Google Search Console verifiziert.
philippkahle, deploy.ufw limit./var/log/auth.log, /var/log/nginx/*.data/users.json.seed_admin.php.data/site.json.site_public.php.data/ per nginx gesperrt.HTML/CSS-Frontend, dynamisch hydrierbar. Projektkarten & Overlays mit Tabs Überblick/Bilder/Details.
Ollama lokal, Modell qwen2:0.5b.
Anbindung über chat_proxy.php.
Persona: „Philipp Kahle, Informatikstudent in Hannover“.
Website-Inhalte als Kontext, History-Trim aktiv.
robots.txt: Admin-Bereich blockiert.sitemap.xml: IDs & Pfade korrigiert.Der vServer ist stabil, sicher und modular: nginx + HTTPS, Security-Header, UFW, Fail2Ban, sicheres Login-System, JSON-CMS, lokale KI.