Ein Fantasy-Labyrinth, das im Browser aus einem Seed entsteht, in PostgreSQL nur seine Deltas speichert und von KI-NPCs mit eigener Seele bevölkert wird. Kein Spritesheet-Ordner, kein Build-Zwang – nur Apache, PHP 8.3, PostgreSQL 16 und viel Vanilla JavaScript.
NPCs bekommen persönliche Porträts, die deutsche Aussprache wird vorbereitet, und eine gemeinsame Steckbrief-Ebene trägt künftig Wesen und Gegenstände.
Gesprächspartner erhalten ein erzeugtes Steckbrief-Foto: ein Textmodell beschreibt das Aussehen, daraus entsteht deterministisch ein Bildprompt, und ein Bildmodell zeichnet. Die Bilder hängen an einer diskreten Tag-Signatur (je ein Wert aus Größe, Farbe, Material und Spezies) statt an jedem einzelnen NPC – so bleibt der Wertebereich klein statt astronomisch. Mit dem Chroma-Screen-Preset wird der Hintergrund serverseitig entfernt und das Bild als freigestellter Avatar neben Beschreibung, Chat und Handel gezeigt.
Der Spielpfad blockiert nicht mehr, sondern reiht nur einen Job ein; ein entkoppelter Cron-Worker erzeugt die Bilder stapelweise. Fehlt noch ein Bild, zeigt der Client einen Platzhalter mit Banderole „wird noch erzeugt". Bestehende NPCs lassen sich per Knopf oder CLI nachziehen (Backfill). Harte Limits – Rate, Tages-/Gesamtbudget, Disk-Quote und Dedup – greifen unverändert am Übergabepunkt.
Die vorhandenen Stimmen (Kokoro) sind englisch; Umlaute, ß, z/w/v,
ch und Zahlen würden falsch gesprochen. Deshalb eine portable
Aussprache-Vorbehandlung: deutscher Text wird so umgeschrieben, dass die
englische Lautschrift ihn näherungsweise deutsch spricht („Häuser" → „Hoiser").
Lexikon, Regelwerk, Profil-Stufen, CLI-Harness, lokale Review-GUI und Tests stehen –
bewusst noch nicht in die Sprachausgabe verdrahtet.
Eine neue Steckbrief-Ebene dient als gemeinsame Zwischenrepräsentation: Jede Entität – Item, Objekt, Ort, Kreatur oder Person – beschreibt kurz ihr Aussehen (Silhouette, Farben, Material, Merkmale, Größe) plus Lore und Tags. Aus derselben Quelle speisen sich Bild-/SVG-Erzeugung und Textpipelines; der Bildprompt liest dabei ausschließlich das Aussehen, nie die Lore. Ein striktes Gate erzwingt Mindestinhalte je Domäne.
Der Beast-Generator liefert jetzt einen validierten Steckbrief; das prozedurale SVG entsteht aus dessen Farben und Größe und wird samt Steckbrief gespeichert und gelesen. Boss-Archetyp, Bildprompt und Anzeige kommen damit aus einer Quelle – das Fundament, aus dem später eine einheitliche Wesen-Grafik wächst.
Eine Item-Archetyp-Registry erzeugt Steckbriefe für Gegenstände – der Referenzfall
ist das Bronzeschwert. Einzigartige Waffen und Rüstungen tragen künftig attrs
und eine complexity, die mit der Tiefe ihrer Hintergrundgeschichte wächst:
das Gegenstück zur Persönlichkeit eines NPCs, gespeist aus der Erzählung, aus der der
Gegenstand stammt.
Treffer fühlen sich jetzt unterschiedlich an — und jede Waffe hat ihr eigenes Tempo.
Ein Schlag zeigt einen kurzen Blitz in Schlagrichtung und trifft nur, was in Reichweite und im Trefferbogen liegt. Der Aufprall rüttelt proportional zum angerichteten Schaden; bewegliche Ziele werden zusätzlich zurückgestoßen, wenn die Kraft ihre Masse übersteigt — schwere oder starre Objekte werden nur gerüttelt. Rüstung senkt den Strukturschaden, statt ihn zu ignorieren.
Jede Waffe hat ein eigenes Angriffstempo: der Dolch sticht schnell, das Schwert holt weiter aus. Jeder Hieb kostet Ausdauer; ist sie leer, werden die Angriffe spürbar langsamer. Ausdauer füllt sich nur außerhalb des Kampfes wieder auf. Die Charakterwerte Ausdauer, Geschick und Körperkraft speisen Maximum, Tempo und Wucht.
Alle Kampfwerte liegen in einer gemeinsamen Konfiguration — Formel-Konstanten, Item-Klassen (rostig < eisen < fein je Ausrüstungsteil) und Werte einzelner Wesen und Objekte. Eine eigene Admin-Maske pflegt sie, Abweichungen je Welt sind möglich; der Dolch kommt als neue Waffe hinzu.
Die jüngste Aktualisierung lässt sich vorlesen — mit einem eigenen Sprach-Zugangspunkt.
Auf der Key-Seite lässt sich ein eigener Sprach-Zugangspunkt eintragen: eine gültige Adresse (z. B. ein selbst betriebenes FastKoko/Kokoro lokal oder ein OpenAI-kompatibler Dienst) samt optionalem Schlüssel. Ohne eigenen Zugang bleibt die Sprachausgabe aus — es gibt keinen vom Betreiber gestellten Sprachzugang. Schlüsselwerte werden wie bei BYOK behandelt und nie angezeigt.
Im NPC-Dialog liest ein Knopf die Antwort vor (optional automatisch für neue Antworten). Bis zu drei Stimmen lassen sich mit Gewichtung mischen, dazu ein Tempo; jede Figur kann eine eigene Stimme bekommen, den Standard erben oder stumm bleiben. Standardmäßig ist alles stumm.
Eine lokale Adresse (etwa http://127.0.0.1) funktioniert nur, wenn Parzival auf demselben Rechner läuft; auf einem Server wird eine öffentliche Adresse eingetragen. Es gibt keine vom Betreiber betriebene Brücke — jede und jeder wählt seinen eigenen Weg.
Die jüngste Aktualisierung bündelt wichtige Einstellungen und macht ausgewählte Betriebsinformationen verständlicher.
BYOK-Einstellungen und eine Übersicht zur Verwendung eigener Schlüssel liegen auf einer eigenen Seite. Ein Modell-Preset und öffentliche OpenRouter-Preise ergänzen die Konfiguration; Schlüsselwerte werden nie angezeigt.
Im NPC-Dialog lassen sich tatsächliche, vom eigenen Provider gemeldete Kosten je Antwort und als Summe der angezeigten Antworten sehen. Die Anzeige ist standardmäßig ausgeschaltet und speichert keinen zusätzlichen Verlauf.
Neu erzeugte lokale Sicherungen werden im Regelbetrieb zusätzlich verschlüsselt abgelegt. Weitere Angaben zu Sicherung und Aufbewahrung stehen in der Datenschutzerklärung.
Zeilen im Repo (inkl. Leerzeilen/Kommentaren). Automatisch aus dem Code erzeugt — bin/artikel_stats.php.
Die tragenden Ideen hinter dem Spiel.
Das Grid entsteht vollständig im Browser aus einem Seed (Besitzer + Ebene). Die Datenbank speichert kein Labyrinth, sondern nur Änderungen: geöffnete Truhen, Seelen, Ziele.
js/sim.js · buildGridPostgreSQL 16 hält nur, was vom deterministischen Grundzustand abweicht. Migration beim Deploy per SHA-256 – kein manuelles SQL.
db/schema.sql · bin/migrate.phpNPCs haben eine streng validierte Seele (Stimmung, Vertrauen, Erinnerungen).
Das Modell liefert am Ende jeder Antwort eine Steuerzeile [meta] –
nie sichtbar, nur Steuerdaten.
Nennt ein NPC einen Ort, liefert das Modell zusätzlich [quest].
Der Server normalisiert es, der Client merkt es sich und generiert daraus
ein Ziel (Marker + Versteck).
Statt alles Weltwissen dauerhaft in den Prompt zu schreiben, fließen nur Einträge ein, deren Stichwörter im Gespräch vorkommen – so bleiben NPCs faktentreu, ohne den Kontext zu sprengen.
inc/lore.php · pz_lore_blockDer System-Prompt wird aus benannten Slots in Reihenfolge gebaut; Vorlagen setzen eine „Author's Note" nahe der Antwort und können Verlauf mit Namen kennzeichnen – die Basis für Gruppen-Chats.
inc/context.php · pz_context_templateEin NPC kann nicht alles mitschleppen, was je gesagt wurde. Darum wird jede verdichtete Erinnerung in eine Zahlenreihe (einen „Vektor") umgewandelt und abgelegt. Kommt später ein Thema zur Sprache, holt eine Ähnlichkeitssuche nur die passenden Erinnerungen hervor – so bleibt der NPC bezogen, ohne zu vergessen und ohne Stichwortliste.
inc/memory.php · pgvectorAssets sind skalierbare SVGs; Waffen/Schild werden am Spieler-Rig verankert und der Angriffs-Swing läuft über die Web Animations API (sauber cancel-/neustartbar).
WAAPI · RIG_ANCHORSWas ein NPC erzählt, wird zu strukturierten Fakten (Subjekt–Relation–Objekt)
und geteiltem Weltwissen. Über eine [facts]-Steuerzeile extrahiert,
strikt normalisiert und als eigener Prompt-Slot worldfacts wieder
eingespeist – so wächst eine konsistente Welt aus den Gesprächen selbst.
Statt NPCs endlos autonom reden zu lassen, wird ein Gespräch nur auf Spieleraktion ausgelöst: Stehen zwei Figuren beieinander und der Spieler in Hörweite, entsteht prozedural (oder per LLM) ein kleines Gespräch und legt neues Wissen offen – kostenfrei, wenn niemand zuhört.
inc/ambient.php · pz_ambient_proceduralGerüchte füllen einen Quest-Pool, der zunächst unsichtbar bleibt. Erst wenn der Wissensstand des Spielers die Anforderungen erfüllt, wird daraus „Neue Spur entdeckt" – getrennt von der Generierung, rein regelbasiert.
inc/quests.php · pz_quests_discovery_syncEin NPC-Satz wird nicht automatisch zur objektiven Wahrheit: Aussagen
(world_claims) und Überzeugungen (beliefs) werden
getrennt geführt. Der Prompt speist NPCs mit ihrem Glauben – so dürfen
sie sich irren oder lügen, und selbst eine Spielerbehauptung wie ein falscher
Name wird gemerkt, ohne je Kanon zu werden.
Bisher „passierte" ein NPC nur, wenn der Spieler hinsah. Ein gebundener,
abschaltbarer Lauf weckt zeitgesteuert fällige Figuren: Sie hören beiläufig
ein Gerücht, das Modell schlägt eine Deutung vor, die Engine
committet genau eine Aussage (evidence_type) und einen
daraus abgeleiteten Glauben – atomar. Die objektive Wahrheit bleibt
unangetastet; ohne Spielerinteraktion entsteht dennoch eine
rekonstruierbare Spur.
Statt „war die Antwort schön?" misst ein Offline-Harness das
Verhalten: Er spielt feste Szenarien durch den Wahrnehmungs-Kreis und
leitet Marker ab – rein regelbasiert aus dem, was die Engine tatsächlich
getan hat, ergänzt um optionales Modell-Reasoning. Jeder Marker trägt einen
Beleg (Engine-ID oder Trace-Stelle); fehlende Evidenz heißt ausdrücklich
not_observable, nie stillschweigend „nein". Kontraste
(z. B. ein widersprechender bestehender Glaube) und
Wiederholungs-Streuung machen Stellschrauben sichtbar – ohne
Produktionsdaten zu berühren.
Derselbe Fakt in zwei Sprachen („Der Schmied hat gestohlen" / „the smith stole") würde Dedupe und Discovery sonst in Varianten zerfallen lassen. Freie Relationen werden auf kanonische Keys abgebildet, Entitäten über eine Alias-Tabelle verknüpft; der Prompt gibt kanonische Welt-Namen vor. Die Entscheidung bleibt symbolisch – kein Vektor, der Stil als Bedeutung liest.
inc/worldfacts.php · fact_relationsWie heiß ist ein Gerücht? Ein rein regelbasiertes Scoring auf der Fakten-Ebene zählt Quellen, Gläubige, Weitergabe-Tiefe und kontrollierte Mutation – mit Aktualitäts-Zerfall. Ab einer Schwelle wird es „heiß" (Saatgut für Quest/Boss), ganz ohne Embedding-Kosten.
inc/rumor.php · rumor_scoresBereits gespeicherte Sprach-Duplikate („Schmied"/„smith") findet der Server per Embedding-Nähe – aber nur als Vorschlag. Das Zusammen- führen passiert auditiert und symbolisch: Fakten, Aussagen, Scores und Aliase werden konsolidiert. Unscharf finden, scharf entscheiden.
inc/entitymerge.php · entity_merge_suggestionsStreuen viele unabhängige Welten dasselbe Gerücht, wächst daraus ein globaler Kreatur-Archetyp: Themen werden owner-gedämpft und log-gewichtet korroboriert, ein strukturierter Lore-Check filtert Unpassendes aus, dann entsteht Lore/Stats/SVG einmalig als wiederverwendbares Template. Abuse (koordinierte „Drachenbeschwörung") erzwingt Review statt Auto-Freigabe.
inc/topics.php · inc/beast.phpSobald ein Archetyp einmal existiert, wird er schnell freischaltbar: in einer neuen Welt wird er als Gerücht verankert und ist damit prompt- und questfähig. Ein eskaliertes Gerücht erzeugt dann eine Boss-Quest mit Archetyp-Referenz; der Client leitet aus ihr ein Ziel ab und stellt den Boss dort auf – kein Zufalls-Spawn. Wird im Hintergrund etwas ausgelöst, meldet es eine dezente Systembenachrichtigung.
inc/quests.php · world_beast_anchorsRegale und Kisten sind seed-deterministisch – die Datenbank merkt sich nur, welche Buchinstanz in welchem Slot liegt. Ein Buch ist kein Fakt, sondern ein gerenderter Blick aufs Weltwissen: Es entsteht gebündelt (ein Modell-Aufruf für mehrere kurze Bücher) aus ausgewählten Fakten der eigenen Welt, wird geprüft und liegt dann als Vorrat bereit. Geöffnet zeigt es einen lesbaren Text mit Verfasser und Glaubwürdigkeit.
inc/lorebooks.php · lore_booksEin Buch lässt sich zerstören (verbrennen, zerreißen …). Das Objekt verschwindet, doch die Tat wird Weltgeschichte: Der alte Zustand wird zeitlich beendet und ein Ereignisfakt angelegt. Was früher „das Buch liegt im Turm" war, ist nun „wurde von X verbrannt" – und kann selbst wieder zur Vorlage für ein neues Buch im Vorrat werden. Kein Buchtext fließt je in Fakten zurück.
inc/lorebooks.php · world_facts.valid_untilWeltwissen ist nicht für immer starr: Jeder Fakt hat ein von und ein bis. Die normale Weltbeschreibung sieht nur, was jetzt gilt; Erinnerung und Chronik finden weiterhin, was vergangen ist. So bleibt ein zerstörtes Buch als Gegenstand weg, während „es existierte" und „wurde verbrannt" dauerhaft wahr bleiben.
inc/worldfacts.php · pz_worldfacts_endAus einer Zerstörung kann ein Rückstand bleiben: Asche, Fetzen, Splitter. Er liegt als einheitlich markiertes Bodenobjekt in der Welt – mit eindeutigem Zustand (liegt / getragen / übergeben / zerstört). Solche Artefakte und späteren Questgegenstände sind unvergänglich, während gewöhnliches Loot nach einer Weile verfällt. Damit sind die Bausteine für mehrstufige Aufträge da: finden, zerstören, Beweis bringen.
inc/worlditems.php · world_itemsDie Vorbereitung ist gelegt: Ein Artefakt kennt attrs und eine
complexity, die mit der Tiefe seiner Hintergrundgeschichte
wachsen kann. Später bekommt eine einzigartige Waffe oder Rüstung so ihre
Werte aus der Lore, aus der sie stammt – ein „Pendant" zur Persönlichkeit
eines NPCs. Erst die Bücher, dann Schritt für Schritt die Gegenstände.
Jeder LLM-Aufruf wird fein granuliert protokolliert (Aktion, Tokens, Kosten, keine Inhalte). Das Admin-Panel zeigt Spitzenstunden und Verbrauch je Aktion; für NPC-zu-NPC-Aktionen greifen harte Ratenlimits mit automatischem Rückfall auf die prozedurale Variante.
inc/telemetry.php · llm_eventsProzedurale Räume werden zu benannten Orten aufgewertet: Wohnraum, Laden, Rattenloch, Krypta, Höhle – mit Einrichtung, Bewohner und Respawn-Regeln.
js/roomarchetypes.jsMenschen haben ein Zuhause und pendeln: zu Hause ⇄ Ausflug, Pfad über eine DOM-freie BFS, Kollision als Sicherheitsnetz.
Sim.findPath · updateNpcAiThemes färben ausschließlich über --pz-*-Variablen; jede
nutzersichtbare Zeile läuft durch pz_t()/pzT() (DE/EN).
PDO-Prepared-Statements, Ausgabe-Escaping, CSRF (Double-Submit), HttpOnly- Cookies, Brute-Force-Limits, SSRF-Schutz für BYOK, keine Modell-Ausführung.
inc/auth.php · inc/llm_user.phpNPC-Antworten lassen sich vorlesen. Gesprochen wird ausschließlich über den eigenen Zugangspunkt (lokales FastKoko/Kokoro oder ein OpenAI-kompatibler Dienst) — kein Betreiber-Schlüssel. Bis zu drei Stimmen werden mit Gewichtung gemischt, dazu ein Tempo; jede Figur erbt den Standard, bekommt eine eigene Stimme oder bleibt stumm.
inc/tts.php · api/tts.phpVom Browser bis zur Datenbank – und zurück als reine Steuerdaten.
Der Spielzustand entsteht client-seitig aus dem Seed; die DB kennt nur Abweichungen. Das hält Levelwechsel billig und das Schema klein.
Vom Login bis zum Kampf – ein zusammenhängender Baukasten.
Registrierung, Login, Google-OAuth, Avatare, Profil, Kontolöschung; Login-Limits und Registrierungs-Sperre pro IP; Sessions als HttpOnly-Cookie.
Einmalige Erstellung: Statur, Geschlecht, Elternberuf → das Modell schreibt eine Hintergrundgeschichte und verteilt Attribute/Multiplikatoren.
Deterministische Seelen, LLM-Dialog, Beziehungswerte (Zuneigung, Vertrauen, Furcht, Respekt), abstrahierte Ereignisse, Aufbewahrungsfristen.
Frühere Begegnungen werden verdichtet, als Vektor gespeichert und bei Bedarf wieder hervorgeholt; periodisch entsteht daraus ein Langzeitgedächtnis. Was früher mit dem Gespräch endete, bleibt jetzt.
Meilenstein erreichtEin optionaler, gebundener Lauf lässt NPCs auch ohne Spieler wirken: fällige Figuren nehmen ein Gerücht wahr und verarbeiten es zu einer Aussage plus Glauben, ohne die Wahrheit zu setzen. Nur Welten mit ausdrücklichem Opt-in des Eigentümers laufen; Quoten, ein Lock und ein Konvergenz-Schutz begrenzen Kosten und Aufschaukeln.
Meilenstein erreichtDie Landing-Page zeigt zweisprachige Artikel mit Themenblöcken und eine KI-Bildergalerie („Impressionen", mit Metadaten und Signatur) sowie das animierte Weltgedächtnis. Ein isoliertes Community-Board (eigene SQLite-DB) bietet Threads mit Antwortbaum, Suche, Moderation, Mute und Audit.
Kauf/Verkauf mit Beziehungspreisen, 4 Inventar-Slots + Beutel, Ausrüstung für Kopf und Hände, Waffen-/Schild-Wirkung.
Sechs Layout-Stile (u. a. Maze, Hallen, Zellen, Wiese, offene Siedlung), Türen & Schalter, Nebel des Krieges mit dynamischem Licht.
Wohnraum, Händlerladen, Rattenloch, Grabanlage, Höhle – mit Möbeln, Bewohnern, Heimat und Respawn (inkl. Miniboss-Regel).
Chance-basiert und seed-deterministisch: versiegelte Kammern hinter versteckten Türen (Annäherung oder Untersuchen), Blutspuren, versteckte Fallen und prozedurale Dialog-NPCs – selten statt überall, in Heimat und Dungeon, mit persistentem Zustand für angemeldete Konten. Ein Baustein-Katalog spiegelt den Validator des Raid-Formats und dient als Grundlage für den künftigen Level-Editor.
Kampfmodus per Taste C/Knopf; Hiebe treffen nur in Reichweite und im Trefferbogen, zeigen einen kurzen Richtungs-Blitz und rütteln proportional zum Schaden. Wucht und Masse entscheiden über den Rückstoß, Rüstung senkt den Strukturschaden. Jede Waffe hat eigenes Angriffstempo und Ausdauerkosten (bei 0 Ausdauer langsamer); Ausdauer füllt sich außerhalb des Kampfes wieder. Bei 0 HP durchgestrichen → transparent → entfernt, kein Loot.
Codex schaltet Wirkung/Struktur durch Untersuchen frei; Hinweis-Ziele aus Dialogen werden serverseitig je Konto/Welt gemerkt und per Nähe erfüllt. Entdeckte Weltspuren und bekanntes Weltwissen füllen die Wissensanzeige.
Regale und Kisten enthalten lesbare Bücher aus dem Weltwissen (Vorrat, keine Live-Generierung). Bücher lassen sich zerstören; die Tat wird zum zeitlich gültigen Ereignisfakt, je nach Methode bleibt ein Artefakt (Asche, Fetzen, Splitter) als unvergängliches Bodenobjekt zurück.
Meilenstein erreichtEin animierter „Cortex" auf der Startseite wächst mit dem geteilten Wissen und ein Holo-Terminal zeigt öffentliche Kennzahlen (Fakten, Erinnerungen, Seelen, Spuren) – live aus der Datenbank, ohne sensible Daten.
Admin-Panel (LLM-Config, Benutzer, Assets, Kosten-&-Peak-Dashboard), Backup/Restore per pg_dump/psql, Auto-Migration, Docker/Coolify-Deploy.
Zeit & Logs: Die Systemzeit liefert die
Virtuozzo-Hostumgebung (1blu); der Host läuft auf
Europe/Berlin (CEST). Container-/Coolify-Logs zeigen
Zeitstempel teils in UTC (+2 h Sommerzeit) – das ist Logformat, kein
Uhrzeitfehler. Ein eigenes NTP ist im Container bewusst nicht aktiv
(ConditionVirtualization=!container); die Hostumgebung
synchronisiert die Uhr.
Verteilung der 90.718 Zeilen über die Schichten. Automatisch erzeugt. Antippen/Überfahren zeigt Name und Zeilen.
| Schicht | Zeilen | Anteil |
|---|---|---|
| PHP-Backend (inc/) | 30.600 | 33,7 % |
| Client-JS (Spiel) | 14.144 | 15,6 % |
| Doku (*.md) | 12.398 | 13,7 % |
| Tests | 12.381 | 13,6 % |
| Admin-Panel | 5.593 | 6,2 % |
| Client-Assets | 5.514 | 6,1 % |
| API-Endpunkte | 3.839 | 4,2 % |
| Spiel-CSS | 2.328 | 2,6 % |
| DB-Schema | 2.173 | 2,4 % |
| OAuth + Root-PHP | 1.748 | 1,9 % |
| Summe | 90.718 | 100,0 % |
| Kategorie | Anzahl |
|---|---|
| SVG-Assets | 71 |
| Client-JS-Dateien | 20 |
| PHP-Backend-Dateien | 74 |
| API-Endpunkte | 25 |
| Admin-Seiten | 9 |
| Sprachdateien (DE/EN) | 2 |
| SQL-Dateien | 2 |
| Wegweiser-/Konzept-Dokumente | 45 |
Ein Check ist ein benannter Testfall (pz_check/pz_db_check in PHP, check() in Node), der in einem echten Lauf bestanden wurde. Node-Suiten laufen host-seitig, PHP-Suiten im App-Container.
Stand des Testlaufs: 2026-10-05T14:12:29+00:00
| Art | bestanden | übersprungen | fehlgeschlagen |
|---|---|---|---|
| PHP-Unit (42 Suiten) | 430 | 0 | 0 |
| PHP-DB (24 Suiten) | 150 | 0 | 0 |
| Node (Client) (14 Suiten) | 966 | 0 | 0 |
| Summe (80 Suiten) | 1.546 | 0 | 0 |
Ausgeführt gesamt: 1.546 Checks. „Bestanden" ist die veröffentlichte Kennzahl; übersprungene (nur mit DB-Opt-in ausgeführte) und fehlgeschlagene Checks sind hier separat ausgewiesen.
| Suite | Art | bestanden | übersprungen | fehlgeschlagen |
|---|---|---|---|---|
| sim.test.js | Node (Client) | 305 | 0 | 0 |
| npctypes.test.js | Node (Client) | 200 | 0 | 0 |
| raid.test.js | Node (Client) | 173 | 0 | 0 |
| rules.test.js | Node (Client) | 74 | 0 | 0 |
| vocab.test.js | Node (Client) | 50 | 0 | 0 |
| entitydesc.test.js | Node (Client) | 35 | 0 | 0 |
| community_store_test.php | PHP-Unit | 35 | 0 | 0 |
| lobby.test.js | Node (Client) | 28 | 0 | 0 |
| content_test.php | PHP-Unit | 23 | 0 | 0 |
| beast_test.php | PHP-Unit | 21 | 0 | 0 |
| impressionen_test.php | PHP-Unit | 20 | 0 | 0 |
| sigil.test.js | Node (Client) | 18 | 0 | 0 |
| llm_test.php | PHP-Unit | 18 | 0 | 0 |
| npcportrait_test.php | PHP-Unit | 18 | 0 | 0 |
| tts_test.php | PHP-Unit | 18 | 0 | 0 |
| npc_test.php | PHP-Unit | 17 | 0 | 0 |
| attrs.test.js | Node (Client) | 16 | 0 | 0 |
| quests.test.js | Node (Client) | 16 | 0 | 0 |
| community_test.php | PHP-Unit | 16 | 0 | 0 |
| worldcaps_db_test.php | PHP-DB | 16 | 0 | 0 |
| worldknowledge.test.js | Node (Client) | 15 | 0 | 0 |
| lorebooks_test.php | PHP-Unit | 15 | 0 | 0 |
| roomarchetypes.test.js | Node (Client) | 14 | 0 | 0 |
| levelfeatures.test.js | Node (Client) | 13 | 0 | 0 |
| diagnose_test.php | PHP-Unit | 13 | 0 | 0 |
| pronunciation_lexicon_test.php | PHP-Unit | 13 | 0 | 0 |
| pronunciation_test.php | PHP-Unit | 13 | 0 | 0 |
| admin_db_test.php | PHP-DB | 11 | 0 | 0 |
| auth_test.php | PHP-Unit | 11 | 0 | 0 |
| items_test.php | PHP-Unit | 11 | 0 | 0 |
| lorebooks_db_test.php | PHP-DB | 10 | 0 | 0 |
| missions_test.php | PHP-Unit | 10 | 0 | 0 |
| portrait_backfill_test.php | PHP-Unit | 10 | 0 | 0 |
| goldenhash.test.js | Node (Client) | 9 | 0 | 0 |
| groupchat_test.php | PHP-Unit | 9 | 0 | 0 |
| i18n_consent_test.php | PHP-Unit | 9 | 0 | 0 |
| pulse_db_test.php | PHP-DB | 9 | 0 | 0 |
| auth_db_test.php | PHP-DB | 8 | 0 | 0 |
| backup_job_test.php | PHP-Unit | 8 | 0 | 0 |
| character_test.php | PHP-Unit | 8 | 0 | 0 |
| entitydesc_test.php | PHP-Unit | 8 | 0 | 0 |
| genqueue_db_test.php | PHP-DB | 8 | 0 | 0 |
| memory_db_test.php | PHP-DB | 8 | 0 | 0 |
| memory_test.php | PHP-Unit | 8 | 0 | 0 |
| npcfacts_test.php | PHP-Unit | 8 | 0 | 0 |
| worlditems_db_test.php | PHP-DB | 8 | 0 | 0 |
| worldkeys_db_test.php | PHP-DB | 8 | 0 | 0 |
| combat_config_test.php | PHP-Unit | 7 | 0 | 0 |
| content_meta_test.php | PHP-Unit | 7 | 0 | 0 |
| keys_test.php | PHP-Unit | 7 | 0 | 0 |
| pulse_test.php | PHP-Unit | 7 | 0 | 0 |
| crypto_test.php | PHP-Unit | 6 | 0 | 0 |
| invites_db_test.php | PHP-DB | 6 | 0 | 0 |
| level_seed_test.php | PHP-Unit | 6 | 0 | 0 |
| npc_restock_test.php | PHP-Unit | 6 | 0 | 0 |
| rumor_test.php | PHP-Unit | 6 | 0 | 0 |
| specialnpc_db_test.php | PHP-DB | 6 | 0 | 0 |
| stepup_db_test.php | PHP-DB | 6 | 0 | 0 |
| worldfacts_temporal_db_test.php | PHP-DB | 6 | 0 | 0 |
| worldfacts_test.php | PHP-Unit | 6 | 0 | 0 |
| diagnose_db_test.php | PHP-DB | 5 | 0 | 0 |
| level_loot_test.php | PHP-Unit | 5 | 0 | 0 |
| worlditems_test.php | PHP-Unit | 5 | 0 | 0 |
| worldvisits_db_test.php | PHP-DB | 5 | 0 | 0 |
| lasur_db_test.php | PHP-DB | 4 | 0 | 0 |
| level_features_db_test.php | PHP-DB | 4 | 0 | 0 |
| memcheck_test.php | PHP-Unit | 4 | 0 | 0 |
| npc_restock_db_test.php | PHP-DB | 4 | 0 | 0 |
| realtime_admin_test.php | PHP-Unit | 4 | 0 | 0 |
| realtime_db_test.php | PHP-DB | 4 | 0 | 0 |
| world_db_test.php | PHP-DB | 4 | 0 | 0 |
| community_isolation_test.php | PHP-Unit | 3 | 0 | 0 |
| genqueue_test.php | PHP-Unit | 3 | 0 | 0 |
| invites_test.php | PHP-Unit | 3 | 0 | 0 |
| level_loot_db_test.php | PHP-DB | 3 | 0 | 0 |
| npcfacts_db_test.php | PHP-DB | 3 | 0 | 0 |
| totp_test.php | PHP-Unit | 3 | 0 | 0 |
| content_groups_db_test.php | PHP-DB | 2 | 0 | 0 |
| oauth_db_test.php | PHP-DB | 2 | 0 | 0 |
| updates_test.php | PHP-Unit | 2 | 0 | 0 |
PHP-Lint und weitere Werkstatt-Prüfungen gehören ins Preflight-Gate (bin/preflight.ps1) und zählen nicht in diese Kennzahl.
| Registry | Steuert | Einträge |
|---|---|---|
| module/labyrinth/js/roomtypes.js | Boden/Wand-Materialien (Grid-Werte, SVGs) | 6 |
| module/labyrinth/js/leveltypes.js | Layout-Arten, Orte-Zuteilung, Bevölkerung/Respawn | 5 |
| module/labyrinth/js/roomarchetypes.js | Orte (Zweck, Möbel, Bewohner, Dienst) | 5 |
| module/labyrinth/js/overlaytypes.js | Overlays + Möbel/Deco | 19 |
| module/labyrinth/js/npctypes.js | NPC-Vorlagen (Menschen + Kreaturen) | 9 |
| module/labyrinth/js/items.js | Items (Wert, Slot, Wirkung) + Truhen-Loot | 15 |
| module/labyrinth/js/abilities.js | Fähigkeiten (Slots) | 1 |
Neue Inhalte sind meist ein Eintrag in einer zentralen Konfiguration. Die vollständige, automatisch erzeugte Übersicht steht in Abschnitt 05 („Konfig-Registries") — eine Quelle statt doppelter Handpflege.
Wendepunkte, an denen aus einfachen Mechaniken ein zusammenhängendes, selbsttragendes System wurde. Der jüngste Meilenstein: NPCs bekommen eine vorlesbare Stimme – per BYOK und je Figur einstellbar.
Bis hierher lebten die NPCs nur als Text. Dieser Schritt gibt ihnen eine hörbare Stimme — aber ohne dass der Betreiber einen Sprachzugang stellt. Ganz im Geist von BYOK trägt jede und jeder den eigenen Zugangspunkt ein: eine gültige Adresse (ein selbst betriebenes FastKoko/Kokoro oder ein OpenAI-kompatibler Dienst) samt optionalem Schlüssel. Ohne eigenen Zugang bleibt es still — die Sprachausgabe ist an dieselbe BYOK-Freigabe gekoppelt und schaltet sich sonst ab.
Der interessante Teil ist die Abstufung. Global wird einmal die Verbindung und optional eine Standard-Stimme festgelegt — bis zu drei Stimmen, die mit relativer Gewichtung zu einer Klangfarbe gemischt werden, dazu ein Tempo. Im Dialog kann dann jede Figur einzeln übersteuern: eine eigene Stimme bekommen, den Standard erben oder explizit stumm bleiben. So spricht am Ende nur, wer sprechen soll — der Wirt mit einer wiedererkennbaren Stimme, alle anderen schweigen, bis man es anders möchte.
Technisch bleibt es bescheiden: Der Text geht an den selbst gewählten Endpunkt und kommt als Audio zurück, das der Browser abspielt; ein Knopf an jeder Antwort liest vor, ein Opt-in liest neue Antworten automatisch. Bei den Stimm-Reglern bleibt ausdrücklich Luft nach oben — eine echte Stimm-Modulation ist als spätere Ausbaustufe vorgemerkt, nicht als Haken dieses Schritts.
Die heikelste Stelle ist die Adresse selbst. Weil sie frei wählbar ist, gilt derselbe Anspruch wie beim übrigen BYOK: nur gültige Ziele, DNS aufgelöst und jede IPv4-/IPv6-Adresse geprüft, gepinnt gegen DNS-Rebinding, keine Redirects, klare Fehler statt leerer Dateien — und lokale Adressen niemals für fremde Konten.
Der stillste und vielleicht folgenreichste Schritt: NPCs existieren nicht
mehr nur, wenn jemand hinsieht. Ein gebundener, abschaltbarer Lauf
weckt zeitgesteuert fällige Figuren; sie hören beiläufig ein Gerücht, das
Modell schlägt eine Deutung vor, die Engine committet genau
eine Aussage samt evidence_type und einen Glauben – atomar,
ohne je die objektive Wahrheit anzufassen. Zum ersten Mal geschieht etwas
zwischen zwei Begegnungen, und es bleibt rekonstruierbar.
Der eigentliche Gewinn war nicht die Mechanik, sondern ihre
Messbarkeit: Ein Offline-Harness spielt feste Szenarien
durch diesen Kreis und übersetzt das Ergebnis in Verhaltens-Marker –
epistemische Sicherheit, Quellen-Skepsis, Intentionsbildung. Noch nicht
beobachtbare Achsen (z. B. bewusste Rückhaltung oder die Behandlung
eines Widerspruchs) weist er ausdrücklich als solche aus, statt sie zu
behaupten. Jeder Marker hat einen Beleg (Engine-ID oder
Reasoning-Stelle); fehlt die Evidenz, steht dort not_observable
statt eines stillen „nein".
Der erste Testlauf hat sich sofort bezahlt gemacht. Ein Reasoning-Modell verbrauchte bei zu knappem Ausgabe-Budget alles fürs Denken und lieferte leeren Text – die Engine griff still auf den prozeduralen Fallback zurück. Gemessen und behoben: die Ausgabegrenzen für Beifang und Gruppenchat wurden angehoben. Ein Kontrast-Test (derselbe Fall mit einem widersprechenden bestehenden Glauben) zeigte außerdem schonungslos eine echte offene Lücke: Weder Engine noch Modell behandeln den Konflikt – das wird zur nächsten Stellschraube. Und der Vergleich zweier Modellgrößen machte sichtbar, dass ein „Denk"-Feld erst dann etwas beiträgt, wenn genug und verlässlich gedacht wird.
NPC-Dialog war bisher immer ein Zweiergespräch; Belauschen gab nur einen flüchtigen Blick auf eine Unterhaltung zwischen anderen. Dieser Schritt macht daraus einen echten, geteilten Verlauf: Der Spieler tritt im Dungeon einer laufenden Unterhaltung mehrerer NPCs bei und kann sich einmischen. Jeder Sprecher behält seine eigene Persona und sein eigenes Gedächtnis, teilt sich aber ein gemeinsames Transkript – mit Namen gekennzeichnet, damit die Beteiligten einander nicht „vergessen".
Technisch ist es bewusst kein einzelner großer Aufruf, sondern ein Modell-Aufruf je Sprecher mit Sprecher-Rotation: So bleibt jede Figur in ihrer Stimme, und der Verlauf wächst wie ein echtes Gespräch. Dazu kommen ein Auto-Modus (Kippschalter + Intervall, standardmäßig aus, der nach einigen Zügen ohne Spielerreaktion von selbst verstummt), Mute je Charakter und das geteilte Lorebook. Der ganze Pfad ist LLM-getrieben und damit serverseitig gesichert.
Der heikle Teil ist die Kosten- und Zugangskontrolle. Die Kosten trägt immer
der Host der Heimatwelt; ohne eigenen Schlüssel greift ein globales,
günstiges Default-Modell als Kostenbremse, und wer BYOK hat, kann per
Namensklick sein eigenes Modell für eine Figur wählen. Gäste dürfen nur
beitreten, wenn der Wirt ihnen die groupchat-Fähigkeit im
Welt-Schlüssel gibt – mit einem Zugbudget, das sich beim Sprechen
verbraucht (erschöpft → gesperrt), und einer Konto-Bestätigung beim
Erstellen oder Ändern des Schlüssels.
Im Betrieb ist der Gruppenchat so aufgeräumt wie alles andere: Gesprächsverläufe werden wie normale Dialoge begrenzt und aufgeräumt (Retention), der Dienst lässt sich zentral drosseln oder abschalten, und der Pfad wurde gehärtet und auditiert.
Bisher war jede Welt implizit „meine“. Dieser Schritt macht sie besuchbar, ohne den Kern zu verwässern: Der Welt-Seed ist jetzt ein zufälliger, nicht aus dem Besitzer ableitbarer Wert, und alles, was per Anfrage sichtbar wird, trägt undurchsichtige Kennungen statt fortlaufender Nummern. Fremde Spielstände lassen sich damit nicht mehr erraten.
Der Zugang läuft über Welt-Schlüssel: Der Wirt erzeugt einen teilbaren, widerrufbaren Schlüssel und entscheidet, welche Rechte er vergibt und ob er abläuft oder einmalig gilt. Ein Gast löst ihn ein und sieht dann die gemeinsam genutzten Zustände der Wirtwelt. Diese erste Stufe ist bewusst asynchron (Wirt und Gast nicht gleichzeitig online) und ohne LLM in fremden Welten: NPC-Dialoge bleiben dem Wirt vorbehalten, Gäste bekommen einen lokalen Hinweis. Ein Wirt-Panel verwaltet die Schlüssel.
Darauf setzt die Realtime-Lobby auf: ein eigener, vom Kern getrennter Dienst hält den prozeduralen Treffpunkt im Speicher und synchronisiert Positionen und Emotes über eine kurzlebige, signierte Eintrittskarte. Der Dienst ist bewusst schlank (fester Seed, kein LLM und kein Gedächtnis) und lässt sich zentral drosseln oder abschalten. Ein Mess-Prototyp hat den Transport vorab auf Belastbarkeit geprüft.
Das Weltgedächtnis wusste bisher nur von Fakten – und nichts davon war lesbar. Dieser Meilenstein macht daraus greifbare Dinge: Bücher, die das gesammelte Weltwissen durch eine Autorenstimme filtern, und Gegenstände, die aus zerstörten Büchern zurückbleiben. Zuerst bekam die Fakt-Ebene ein Gedächtnis für Zeit: Jeder Fakt hat jetzt ein von und ein bis. Die normale Weltbeschreibung sieht nur, was jetzt gilt; Chronik und Erinnerung finden weiterhin, was vergangen ist.
Darauf sitzen die Bücher. Regale und Kisten sind seed-deterministisch, die Datenbank merkt sich nur, welche Buchinstanz in welchem Slot liegt. Ein Buch ist bewusst kein Fakt, sondern ein gerenderter Blick darauf: Ein einziger Modell-Aufruf erzeugt gebündelt mehrere kurze Bücher aus ausgewählten Fakten der Welt, prüft sie (Länge, Gattung, Dopplung, ein kurzer Lore-Filter) und legt sie als Vorrat ab. Beim Öffnen erscheint ein lesbarer Text mit Verfasser und Glaubwürdigkeit – vom Tagebuch bis zum Kneipenlied.
Der eigentliche Kern ist die Zerstörung. Ein Buch kann verbrannt, zerrissen oder zerschlagen werden. Das Objekt verschwindet, doch die Tat wird Geschichte: Der alte Zustand wird zeitlich beendet und ein Ereignisfakt angelegt. Aus „das Buch liegt im Turm" wird „wurde von X verbrannt" – und je nach Methode bleibt ein Rückstand (Asche, Fetzen, Splitter). Nahe NPCs merken sich die Tat als eigene Perspektive. Der Ereignisfakt kann sogar selbst zur Vorlage eines neuen Buchs im Vorrat werden. Kein Buchtext fließt dabei je in Fakten zurück.
Die Rückstände und späteren Questgegenstände liegen als Artefakte in der Welt: einheitlich markiert, mit eindeutigem Zustand (liegt / getragen / übergeben / zerstört). Artefakte und Questobjekte sind unvergänglich, gewöhnliches Loot verfällt nach einer Weile – und bricht ein Auftrag ab, verschwinden seine Objekte sofort. Damit sind die Bausteine für mehrstufige Aufträge gelegt (finden → zerstören → Beweis bringen), ohne die Quests jetzt schon zu verdrahten.
NPCs sind bisher mit einem festen Charakter geboren und vergessen ihre eigenen Erlebnisse. Dieses System gibt ihnen eine über die Zeit wachsende und wieder verblassende Persönlichkeit. Der Trick: Aus jedem Gespräch fallen – als Beifang der ohnehin laufenden Extraktion, ganz ohne Zusatz-Aufruf – winzige Fakten über den NPC selbst ab („wurde gekränkt", „hat etwas versprochen", „mag diesen Ort"). Auch erwähnte andere Wesen werden nur gezählt.
Diese Fakten werden gewichtet (Herkunft × Sicherheit) und verblassen exponentiell. Daraus entsteht ein Persönlichkeits-Score, der zuerst das Verhalten steuert: erfahrenere NPCs fliehen früher aus einem Kampf und verhandeln lieber, statt bis zum Tod zu kämpfen. Klassische Werte wie HP und Rüstung wachsen nur mit geringem Gewicht – so wird ein vielbeschäftigter NPC nicht einfach unbesiegbar.
Verfall ist gekoppelt: Charakterfakten und mechanische Wirkung verblassen gemeinsam. Bekommt ein NPC lange keinen Kontakt, schläft er ein (Winterschlaf); bleibt er es, verblasst er über mehrere Stufen bis zum endgültigen Tod – die Sterblichkeit ist pro NPC-Typ einstellbar. Der Client lässt tote NPCs aus und zeichnet verblasste sichtbar anders. Ein eigenes, vorkonfiguriertes Modell kann die Fakten optional zu einer knappen Charakternotiz verdichten (getrennte Kostenkategorie).
Dieses System schließt den Kreis vom gesprochenen Wort zum spielbaren Gegner. NPCs erzählen Gerüchte; der Server speichert sie nicht als Text, sondern als strukturierte, sprachneutrale Fakten (Subjekt–Relation–Objekt). Verbreitet sich ein Motiv – etwa ein Drache – über viele unabhängige Spielerwelten, wertet das System es nach und nach auf: vom bloßen Gerede über einen regelbasierten Lore-Check bis hin zu einem vollwertigen Gegner-Entwurf.
Klingt ein Thema in genügend unabhängigen Welten an, erzeugt ein Modell einmalig einen wiederverwendbaren Archetyp: Name, Hintergrundgeschichte, Attribute (Kreaturentyp, Element, Rolle), Werte und ein SVG-Abbild. Danach liegt er in einer globalen Registry bereit. Taucht dasselbe Motiv später in einer neuen Welt auf, wird zuerst gegen die Registry gematcht (gleicher Kreaturentyp, Element, Namensstamm) und der vorhandene Archetyp wiederverwendet, statt teuer einen neuen zu erzeugen.
Trifft ein einzelnes Gerücht in einer Welt eine Eskalationsschwelle, wird der Archetyp dort als reales Weltwissen verankert und erzeugt eine Boss-Quest. Der Client leitet daraus ein konkretes Ziel ab und stellt den Gegner an genau dieser Stelle auf – deterministisch, permanent, kein Zufalls-Spawn. Kein Spieler „beschwört" also direkt einen Boss; er trägt über Gespräche dazu bei, dass eine Welt ihn überhaupt hervorbringen kann.
Der heikelste Teil ist Missbrauchsschutz, denn eine Gruppe könnte sich absprechen und koordiniert dasselbe Gerücht pflanzen. Dagegen wirken mehrere Schichten: Gezählt wird nach unabhängiger Welt, nicht nach Konto; mehrere Welten desselben Besitzers zählen nur einfach (Owner-Dämpfung); das Gewicht wächst logarithmisch statt linear und junge Welten wiegen weniger; eine Schwelle, die in Minuten statt Tagen fällt, erzeugt ein Velocity-Flag; ein übergroßes Gerücht sättigt asymptotisch, statt unbegrenzt zu eskalieren. Verdächtige Muster gehen zwingend in Admin-Review statt automatisch live. Ein strukturiertes Lore-Regelwerk filtert Absurdes sofort aus, und die Generierung ist standardmäßig abgeschaltet.
Das Fundament: NPC-Aussagen werden zu geteiltem, strukturiertem Weltwissen. Statt jede Behauptung als Wahrheit zu behandeln, trennt das System Aussage, Glaube und Wahrheit – ein NPC darf sich irren oder lügen, und der Prompt speist ihn mit seinem Glauben, nicht mit rohem Kanon. Spielerwissen, Belauschen, ein Quest-Pool mit rein regelbasierter Discovery und ein Codex für den Spieler runden das ab.
Damit Gerüchte über Sprach- und Stilgrenzen hinweg vergleichbar bleiben, werden Relationen auf kanonische Schlüssel abgebildet und Entitäten über Aliasse verknüpft („Schmied" und „smith" werden dieselbe Entität). Die Bewertung läuft symbolisch auf der Fakten-Ebene – Quellen, Gläubige, Weitergabe-Tiefe und kontrollierte Mutation – statt über unzuverlässige Text-Ähnlichkeit. Korrekturbedarf (Sprach-Duplikate) wird per Embedding-Nähe nur vorgeschlagen; entschieden wird auditiert.
NPCs vergessen nicht mehr am Gesprächsende: Verdichtete Erinnerungen werden als Vektoren gespeichert und bei Bedarf per Ähnlichkeitssuche hervorgeholt, periodisch zu einem Langzeitgedächtnis zusammengefasst. Ein Prompt-Manager baut den System-Prompt aus benannten Slots, ein Lorebook fließen nur passende Weltfakten ein – die Grundlage für konsistente, gruppenfähige Charaktere.
Priorisiert; Details in docs/FEATURES.md.
not_observable statt still „false"), Kontraste und Wiederholungs-Streuung prüft und nichts in Produktion schreibt. Erste Befunde flossen direkt in Fixes (Ausgabe-Budgets für Reasoning-Modelle) und deckten die offene Lücke „widersprechender Glaube" auf.groupchat-Fähigkeit im Welt-Schlüssel mit Zugbudget; Retention, Kill-Schalter und Audit.Kein Framework, kein Bundler im Client. Vanilla JS und UMD-Module bleiben lesbar, testbar und schnell.
Anzeigetexte als Keys, Inhalte in Registries, Assets als Dateien – der Wegweiser hält alles auffindbar.
Jede Client-Interaktion wird gegen Injection, XSS, CSRF und Missbrauch geprüft – Modelltext ist immer Daten, nie Code.