update
This commit is contained in:
parent
7af8e54b6a
commit
d40106445e
604
conzept.html
Normal file
604
conzept.html
Normal file
@ -0,0 +1,604 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Projekt-Blaupause: KI-Krimi-Dinner "Projekt Chimera"</title>
|
||||||
|
<!-- TailwindCSS & Mermaid.js via CDN -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/mermaid@10.9.1/dist/mermaid.min.js"></script>
|
||||||
|
<style>
|
||||||
|
/* Minimal body styles to prevent flash of unstyled content */
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||||
|
background-color: #f9fafb;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-100 text-gray-800">
|
||||||
|
<div class="container mx-auto max-w-7xl p-4 sm:p-8">
|
||||||
|
<div class="bg-white rounded-xl shadow-lg p-6 sm:p-10">
|
||||||
|
|
||||||
|
<header class="mb-10 text-center border-b pb-8">
|
||||||
|
<h1 class="text-4xl sm:text-5xl font-bold text-gray-900">Projekt-Blaupause: KI-Krimi-Dinner "Projekt Chimera"</h1>
|
||||||
|
<div class="mt-6 grid grid-cols-1 sm:grid-cols-3 gap-4 max-w-2xl mx-auto">
|
||||||
|
<div class="bg-gray-50 p-3 rounded-lg">
|
||||||
|
<span class="block text-xs font-semibold text-gray-500 uppercase tracking-wider">Version</span>
|
||||||
|
<span class="text-gray-800 font-medium">3.0 (Final & Complete UI)</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 p-3 rounded-lg">
|
||||||
|
<span class="block text-xs font-semibold text-gray-500 uppercase tracking-wider">Autor</span>
|
||||||
|
<span class="text-gray-800 font-medium">D. Schuhbaum & S. Altschäffl</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 p-3 rounded-lg">
|
||||||
|
<span class="block text-xs font-semibold text-gray-500 uppercase tracking-wider">Datum</span>
|
||||||
|
<span class="text-gray-800 font-medium">03.10.2025</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="mb-10">
|
||||||
|
<h2 class="text-2xl font-semibold text-gray-800 border-b pb-2 mb-4">1. Projektübersicht</h2>
|
||||||
|
<p>"Projekt Chimera" ist ein hybrides Krimi-Dinner-Erlebnis, das physische soziale Interaktion mit einer digitalen App-Komponente verbindet. Das Alleinstellungsmerkmal ist der Einsatz einer zweistufigen KI-Architektur, die nicht nur einzigartige narrative Szenarien generiert, sondern diese auch proaktiv auf logische Konsistenz validiert und korrigiert.</p>
|
||||||
|
<p>Die Architektur basiert auf einer klaren Trennung: <strong>Supabase</strong> dient als dedizierter Service für die Benutzerauthentifizierung, während alle Spieldaten (Szenarien, Spieler, Spielstände) in einer <strong>separaten, dedizierten PostgreSQL-Datenbank</strong> gehostet werden. Ein zentrales <strong>FastAPI-Backend</strong> fungiert als sichere Schnittstelle zwischen den Clients und beiden Diensten.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="mb-10">
|
||||||
|
<h2 class="text-2xl font-semibold text-gray-800 border-b pb-2 mb-4">2. Narratives Design & Validierung</h2>
|
||||||
|
<p>Die Generierung jedes Spiels folgt einem strengen, zweistufigen Prozess, um die narrative Qualität und logische Integrität zu gewährleisten.</p>
|
||||||
|
|
||||||
|
<div class="mt-6 space-y-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-xl font-semibold mb-2">Schritt 1: Kreative Generierung (Der "Autor")</h3>
|
||||||
|
<p>In dieser Phase agiert die KI als kreativer Autor. Sie erhält einen umfassenden Prompt, der die gewünschten Rahmenbedingungen (Szenario-Beschreibung, Rundenanzahl) vorgibt. Die genaue Spieleranzahl wird dynamisch aus der Lobby übernommen, kurz bevor die KI die Generierung startet.</p>
|
||||||
|
<ul class="list-disc list-inside space-y-2 bg-gray-50 p-4 rounded-lg mt-4">
|
||||||
|
<li><strong>Hintergrundgeschichte:</strong> Der Rahmen des Geschehens und der Grund für das Zusammentreffen.</li>
|
||||||
|
<li><strong>Charaktere:</strong> Detaillierte Rollen mit Persönlichkeit, Beziehungen und öffentlichen Informationen.</li>
|
||||||
|
<li><strong>Geheimnisse & Ziele:</strong> Private Geheimnisse und spielrelevante Ziele für jeden Charakter.</li>
|
||||||
|
<li><strong>Der Mord & lückenloser Zeitstrahl:</strong> Definition des Verbrechens und Etablierung eines kontinuierlichen Zeitstrahls für jeden Charakter (z.B. "16:30-16:45: Aktion A"), um Alibis nachvollziehbar zu machen.</li>
|
||||||
|
<li><strong>Beziehungsgeflecht:</strong> Eine Matrix der komplexen Beziehungen zwischen allen Charakteren.</li>
|
||||||
|
<li><strong>Hinweise:</strong> Ein Set von Hinweisen, die den Mörder belasten oder falsche Fährten legen, aufgeteilt auf die gewählte Rundenanzahl.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-xl font-semibold mb-2">Schritt 2: Logische Validierung & Korrektur (Der "Logik-Lektor")</h3>
|
||||||
|
<p>Der rohe Output aus Schritt 1 wird nun an eine zweite KI-Instanz übergeben, die als akribischer Logik-Lektor agiert. Die KI wird instruiert, das gesamte Szenario anhand einer Checkliste von potenziellen Fehlern zu überprüfen:</p>
|
||||||
|
<ul class="list-disc list-inside space-y-2 bg-gray-50 p-4 rounded-lg mt-4">
|
||||||
|
<li><strong>Widersprüche in Zeitlinien:</strong> Passen Alibis und die Zeitblöcke auf den Zeitstrahlen aller Charaktere lückenlos und widerspruchsfrei zusammen?</li>
|
||||||
|
<li><strong>Motiv-Konsistenz:</strong> Ist das Motiv des Mörders stark genug und logisch begründet?</li>
|
||||||
|
<li><strong>Hinweis-Validität:</strong> Führt mindestens ein entscheidender Hinweis logisch zum Täter? Sind falsche Fährten subtil?</li>
|
||||||
|
<li><strong>Charakter-Konsistenz:</strong> Handeln die Charaktere gemäß ihrer beschriebenen Persönlichkeit und Ziele?</li>
|
||||||
|
<li><strong>Regelkonformität:</strong> Ist das Spiel fair und lösbar?</li>
|
||||||
|
</ul>
|
||||||
|
<p class="mt-4">Die KI korrigiert gefundene Fehler minimalinvasiv, um die kreative Essenz nicht zu verändern, und gibt ein logisch wasserdichtes Spielszenario aus.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="mb-10">
|
||||||
|
<h2 class="text-2xl font-semibold text-gray-800 border-b pb-2 mb-4">3. Technische Architektur</h2>
|
||||||
|
<p class="mb-4">Die Architektur ist auf maximale Kontrolle und Skalierbarkeit ausgelegt. Die React Native-Clients kommunizieren ausschließlich mit dem FastAPI-Backend. Supabase wird als reiner Authentifizierungs-Provider genutzt. Echtzeit-Updates werden über eine WebSocket-Verbindung vom FastAPI-Server an die Clients gepusht.</p>
|
||||||
|
|
||||||
|
<div class="bg-gray-50 p-4 sm:p-8 rounded-lg w-full overflow-x-auto">
|
||||||
|
<pre class="mermaid text-center">
|
||||||
|
graph TD
|
||||||
|
subgraph "Spieler-Geräte"
|
||||||
|
P1["React Native Apps"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Authentifizierung"
|
||||||
|
Auth["Supabase Auth"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Sicheres Backend"
|
||||||
|
FastAPI["FastAPI Server <br> REST & WebSockets"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Spieldaten-Bank"
|
||||||
|
PG_DB["PostgreSQL DB"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Externe Dienste"
|
||||||
|
OAI["OpenAI API"]
|
||||||
|
end
|
||||||
|
|
||||||
|
%% Verbindungen
|
||||||
|
P1 -- "1. Login" --> Auth
|
||||||
|
P1 -- "2. API Calls (mit Token)" --> FastAPI
|
||||||
|
|
||||||
|
FastAPI -- "3. KI Call" --> OAI
|
||||||
|
FastAPI -- "4. DB-Zugriff" --> PG_DB
|
||||||
|
|
||||||
|
FastAPI -- "5. WebSocket Updates" --> P1
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 class="text-xl font-semibold mt-6 mb-3">Datenfluss-Beschreibung:</h3>
|
||||||
|
<ol class="list-decimal list-inside space-y-3">
|
||||||
|
<li><strong>Authentifizierung:</strong> Der Benutzer authentifiziert sich in der React Native-App direkt bei <strong>Supabase Auth</strong>. Die App erhält ein JWT (JSON Web Token).</li>
|
||||||
|
<li><strong>API-Anfragen:</strong> Für <strong>alle</strong> spielrelevanten Aktionen sendet die App eine Anfrage an den <strong>FastAPI-Server</strong> und fügt das JWT von Supabase in den Authorization-Header ein. FastAPI validiert dieses Token.</li>
|
||||||
|
<li><strong>KI-Generierung:</strong> Für die Spielerstellung ruft der FastAPI-Server die <strong>OpenAI-API</strong> auf.</li>
|
||||||
|
<li><strong>Datenbank-Interaktion:</strong> FastAPI ist die <strong>einzige</strong> Komponente, die mit der <strong>dedizierten PostgreSQL-Datenbank</strong> kommuniziert.</li>
|
||||||
|
<li><strong>Echtzeit-Updates:</strong> Die Clients bauen eine <strong>WebSocket-Verbindung</strong> zum FastAPI-Server auf. Bei Änderungen pusht der Server Updates an alle verbundenen Clients.</li>
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="mb-10">
|
||||||
|
<h2 class="text-2xl font-semibold text-gray-800 border-b pb-2 mb-4">4. User Interface (UI) Konzept</h2>
|
||||||
|
<p class="mb-6">Die UI-Konzepte werden als klare, moderne Wireframes visualisiert, um den gesamten App-Flow von der Erstellung bis zum Spiel darzustellen.</p>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-8">
|
||||||
|
|
||||||
|
<!-- Wireframe 1: Login -->
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg border">
|
||||||
|
<h3 class="text-lg font-semibold mb-3 text-center">1. Login</h3>
|
||||||
|
<div class="bg-white w-full max-w-sm mx-auto aspect-[9/19.5] rounded-2xl shadow-lg p-3 border flex flex-col">
|
||||||
|
<div class="text-center pt-8 pb-6">
|
||||||
|
<h4 class="font-bold text-xl tracking-tight">PROJEKT CHIMERA</h4>
|
||||||
|
</div>
|
||||||
|
<div class="px-3 space-y-3 flex-grow">
|
||||||
|
<input type="text" placeholder="E-Mail-Adresse" class="w-full border rounded-md p-2 text-sm bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||||
|
<input type="password" placeholder="Passwort" class="w-full border rounded-md p-2 text-sm bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||||
|
<button class="w-full bg-blue-600 text-white rounded-md py-2 font-semibold hover:bg-blue-700 transition-colors">Anmelden</button>
|
||||||
|
<p class="text-center text-xs text-gray-500">Noch kein Konto? <a href="#" class="font-semibold text-blue-600">Jetzt registrieren</a></p>
|
||||||
|
</div>
|
||||||
|
<div class="h-8"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Wireframe 2: Registration -->
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg border">
|
||||||
|
<h3 class="text-lg font-semibold mb-3 text-center">2. Registrierung</h3>
|
||||||
|
<div class="bg-white w-full max-w-sm mx-auto aspect-[9/19.5] rounded-2xl shadow-lg p-3 border flex flex-col">
|
||||||
|
<div class="text-center pt-8 pb-6">
|
||||||
|
<h4 class="font-bold text-xl tracking-tight">Konto erstellen</h4>
|
||||||
|
</div>
|
||||||
|
<div class="px-3 space-y-3 flex-grow">
|
||||||
|
<input type="text" placeholder="E-Mail-Adresse" class="w-full border rounded-md p-2 text-sm bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||||
|
<input type="password" placeholder="Passwort" class="w-full border rounded-md p-2 text-sm bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||||
|
<input type="password" placeholder="Passwort bestätigen" class="w-full border rounded-md p-2 text-sm bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||||
|
<button class="w-full bg-blue-600 text-white rounded-md py-2 font-semibold hover:bg-blue-700 transition-colors">Registrieren</button>
|
||||||
|
<p class="text-center text-xs text-gray-500">Bereits ein Konto? <a href="#" class="font-semibold text-blue-600">Zum Login</a></p>
|
||||||
|
</div>
|
||||||
|
<div class="h-8"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Wireframe 3: Home Dashboard -->
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg border">
|
||||||
|
<h3 class="text-lg font-semibold mb-3 text-center">3. Home Dashboard</h3>
|
||||||
|
<div class="bg-white w-full max-w-sm mx-auto aspect-[9/19.5] rounded-2xl shadow-lg p-3 border flex flex-col">
|
||||||
|
<div class="p-4 flex justify-between items-center border-b">
|
||||||
|
<h4 class="font-bold text-lg">Deine Spiele</h4>
|
||||||
|
<button class="text-xs text-gray-500 hover:text-blue-600">Logout</button>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 flex-grow overflow-y-auto space-y-3">
|
||||||
|
<div class="bg-gray-100 border rounded-lg p-3">
|
||||||
|
<p class="font-bold">Tech-Konferenz 2035</p>
|
||||||
|
<p class="text-xs text-gray-600 mt-1">Status: <span class="font-semibold text-green-600">Aktiv (Runde 2/3)</span></p>
|
||||||
|
<button class="w-full mt-2 bg-blue-600 text-white rounded-md py-1 text-sm font-semibold">Weiterspielen</button>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-100 border rounded-lg p-3">
|
||||||
|
<p class="font-bold">Villa Vendetta</p>
|
||||||
|
<p class="text-xs text-gray-600 mt-1">Status: <span class="font-semibold text-gray-500">Lobby (0 Spieler)</span></p>
|
||||||
|
<button class="w-full mt-2 bg-blue-600 text-white rounded-md py-1 text-sm font-semibold">Zur Lobby</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 grid grid-cols-2 gap-3 border-t">
|
||||||
|
<button class="bg-green-100 text-green-800 rounded-md py-2 font-semibold text-sm hover:bg-green-200">Neues Spiel</button>
|
||||||
|
<button class="bg-gray-100 text-gray-800 rounded-md py-2 font-semibold text-sm hover:bg-gray-200">Beitreten</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Wireframe 4: Spiel erstellen -->
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg border">
|
||||||
|
<h3 class="text-lg font-semibold mb-3 text-center">4. Spiel erstellen (Host)</h3>
|
||||||
|
<div class="bg-white w-full max-w-sm mx-auto aspect-[9/19.5] rounded-2xl shadow-lg p-3 border flex flex-col">
|
||||||
|
<div class="text-center pt-4 pb-3 border-b">
|
||||||
|
<h4 class="font-bold text-lg">Neues Spiel erstellen</h4>
|
||||||
|
</div>
|
||||||
|
<div class="px-3 py-4 flex-grow space-y-4">
|
||||||
|
<div>
|
||||||
|
<label class="font-semibold text-sm">Szenario-Beschreibung</label>
|
||||||
|
<textarea placeholder="z.B. Ein Mord auf einer Tech-Konferenz im Jahr 2035..." class="w-full mt-1 border rounded-md p-2 text-sm bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 h-24"></textarea>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="font-semibold text-sm">Rundenanzahl</label>
|
||||||
|
<div class="flex items-center justify-between mt-1">
|
||||||
|
<input type="range" min="2" max="5" value="3" class="w-full">
|
||||||
|
<span class="ml-4 font-bold text-lg w-8 text-center">3</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-gray-500">
|
||||||
|
<p>Die Spieleranzahl ist flexibel (mind. 3 Spieler) und wird in der Lobby durch die Anzahl der beigetretenen Spieler bestimmt.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="px-3 pb-3">
|
||||||
|
<button class="w-full bg-blue-600 text-white rounded-md py-2 font-semibold hover:bg-blue-700 transition-colors">Szenario generieren & Lobby öffnen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Wireframe 5: Host-Lobby (Initial) -->
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg border">
|
||||||
|
<h3 class="text-lg font-semibold mb-3 text-center">5. Host-Lobby</h3>
|
||||||
|
<div class="bg-white w-full max-w-sm mx-auto aspect-[9/19.5] rounded-2xl shadow-lg p-3 border flex flex-col">
|
||||||
|
<div class="text-center pt-4 pb-3 border-b">
|
||||||
|
<p class="text-xs text-gray-500">Spiel-Lobby</p>
|
||||||
|
<h4 class="font-bold text-lg">Tech-Konferenz 2035</h4>
|
||||||
|
</div>
|
||||||
|
<div class="px-3 py-4 text-center flex-grow">
|
||||||
|
<p class="text-sm text-gray-600">Teile diesen Code mit deinen Mitspielern:</p>
|
||||||
|
<div class="my-3 bg-blue-50 border-2 border-dashed border-blue-200 text-blue-800 font-bold text-3xl tracking-widest py-3 rounded-lg">
|
||||||
|
GHY-781
|
||||||
|
</div>
|
||||||
|
<h5 class="font-semibold text-left mt-6 mb-2">Beigetretene Spieler (3)</h5>
|
||||||
|
<ul class="space-y-2 text-left">
|
||||||
|
<li class="bg-gray-100 p-2 rounded-md flex justify-between items-center"><span>Maria</span> <button class="text-red-500 text-xs">Entfernen</button></li>
|
||||||
|
<li class="bg-gray-100 p-2 rounded-md flex justify-between items-center"><span>Jonas</span> <button class="text-red-500 text-xs">Entfernen</button></li>
|
||||||
|
<li class="bg-gray-100 p-2 rounded-md flex justify-between items-center"><span>Sandra</span> <button class="text-red-500 text-xs">Entfernen</button></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="px-3 pb-3 space-y-2">
|
||||||
|
<button class="w-full bg-red-100 text-red-800 rounded-md py-2 font-semibold text-xs hover:bg-red-200">Szenario verwerfen & Neu generieren</button>
|
||||||
|
<button class="w-full bg-green-600 text-white rounded-md py-2 font-semibold">Spiel starten (3 Spieler)</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Wireframe 6: Spieler-Ansicht (Rolle) -->
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg border">
|
||||||
|
<h3 class="text-lg font-semibold mb-3 text-center">6. Spieler-Ansicht (Rolle)</h3>
|
||||||
|
<div class="bg-white w-full max-w-sm mx-auto aspect-[9/19.5] rounded-2xl shadow-lg p-3 border flex flex-col">
|
||||||
|
<div class="p-3 text-center border-b">
|
||||||
|
<p class="text-xs text-gray-400">Deine Rolle</p>
|
||||||
|
<h4 class="font-bold text-lg">Dr. Aris Thorne</h4>
|
||||||
|
</div>
|
||||||
|
<div class="flex border-b">
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold border-b-2 border-blue-600 text-blue-600">Rolle</button>
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold text-gray-400 hover:bg-gray-50">Hinweise</button>
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold text-gray-400 hover:bg-gray-50">Charaktere</button>
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold text-gray-400 hover:bg-gray-50">Zeitstrahl</button>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 flex-grow overflow-y-auto text-sm text-gray-700 space-y-3">
|
||||||
|
<h5 class="font-bold">Deine Ziele:</h5>
|
||||||
|
<ul class="list-disc list-inside text-xs space-y-1">
|
||||||
|
<li>Finde heraus, wer deine Forschung sabotiert hat.</li>
|
||||||
|
<li>Verhindere, dass dein Geheimnis über das gescheiterte Experiment ans Licht kommt.</li>
|
||||||
|
</ul>
|
||||||
|
<h5 class="font-bold pt-2">Deine Geheimnisse:</h5>
|
||||||
|
<p class="text-xs">Du hast vor einem Monat bei einem nicht genehmigten Experiment die Stromversorgung der Station überlastet, was zu einem kritischen Ausfall führte. Nur das Opfer wusste davon.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Wireframe 6: Spieler-Ansicht (Hinweise) -->
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg border">
|
||||||
|
<h3 class="text-lg font-semibold mb-3 text-center">6. Spieler-Ansicht (Hinweise)</h3>
|
||||||
|
<div class="bg-white w-full max-w-sm mx-auto aspect-[9/19.5] rounded-2xl shadow-lg p-3 border flex flex-col">
|
||||||
|
<div class="p-3 text-center border-b">
|
||||||
|
<p class="text-xs text-gray-400">Deine Rolle</p>
|
||||||
|
<h4 class="font-bold text-lg">Dr. Aris Thorne</h4>
|
||||||
|
</div>
|
||||||
|
<div class="flex border-b">
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold text-gray-400 hover:bg-gray-50">Rolle</button>
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold border-b-2 border-blue-600 text-blue-600 relative">Hinweise<span class="absolute top-1 right-2 w-2 h-2 bg-red-500 rounded-full"></span></button>
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold text-gray-400 hover:bg-gray-50">Charaktere</button>
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold text-gray-400 hover:bg-gray-50">Zeitstrahl</button>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 flex-grow overflow-y-auto text-sm text-gray-700 space-y-4">
|
||||||
|
<div>
|
||||||
|
<h5 class="font-bold text-base">Runde 2 (18:00 - 19:00 Uhr)</h5>
|
||||||
|
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-3 mt-2">
|
||||||
|
<p class="font-semibold text-xs text-yellow-800">HINWEIS #3</p>
|
||||||
|
<p class="text-xs text-yellow-900 mt-1">Ein zerrissener Brief wurde gefunden. Die Worte "Schulden" und "letzte Warnung" sind lesbar.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="opacity-60">
|
||||||
|
<h5 class="font-bold text-base">Runde 1 (16:00 - 18:00 Uhr)</h5>
|
||||||
|
<div class="bg-gray-100 border rounded-lg p-3 mt-2">
|
||||||
|
<p class="font-semibold text-xs text-gray-600">HINWEIS #1</p>
|
||||||
|
<p class="text-xs text-gray-700 mt-1">Das Opfer wurde mit einem schweren Gegenstand erschlagen.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Wireframe 7: Spieler-Ansicht (Charaktere) -->
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg border">
|
||||||
|
<h3 class="text-lg font-semibold mb-3 text-center">7. Spieler-Ansicht (Charaktere)</h3>
|
||||||
|
<div class="bg-white w-full max-w-sm mx-auto aspect-[9/19.5] rounded-2xl shadow-lg p-3 border flex flex-col">
|
||||||
|
<div class="p-3 text-center border-b">
|
||||||
|
<p class="text-xs text-gray-400">Deine Rolle</p>
|
||||||
|
<h4 class="font-bold text-lg">Dr. Aris Thorne</h4>
|
||||||
|
</div>
|
||||||
|
<div class="flex border-b">
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold text-gray-400 hover:bg-gray-50">Rolle</button>
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold text-gray-400 hover:bg-gray-50">Hinweise</button>
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold border-b-2 border-blue-600 text-blue-600">Charaktere</button>
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold text-gray-400 hover:bg-gray-50">Zeitstrahl</button>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 flex-grow overflow-y-auto text-sm text-gray-700 space-y-3">
|
||||||
|
<div class="bg-gray-50 border rounded-lg p-3">
|
||||||
|
<p class="font-bold">Evelyn Reed (CEO)</p>
|
||||||
|
<p class="text-xs text-gray-600 mt-1">Die ehrgeizige CEO des Konkurrenzunternehmens. Es ist bekannt, dass sie und das Opfer eine erbitterte Rivalität pflegten.</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 border rounded-lg p-3">
|
||||||
|
<p class="font-bold">Ivan Petrov (Sicherheitschef)</p>
|
||||||
|
<p class="text-xs text-gray-600 mt-1">Der loyale, aber jähzornige Sicherheitschef. Er war für den Schutz des Opfers verantwortlich.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Wireframe 7: Spieler-Ansicht (Zeitstrahl) -->
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg border">
|
||||||
|
<h3 class="text-lg font-semibold mb-3 text-center">7. Spieler-Ansicht (Zeitstrahl)</h3>
|
||||||
|
<div class="bg-white w-full max-w-sm mx-auto aspect-[9/19.5] rounded-2xl shadow-lg p-3 border flex flex-col">
|
||||||
|
<div class="p-3 text-center border-b">
|
||||||
|
<p class="text-xs text-gray-400">Deine Rolle</p>
|
||||||
|
<h4 class="font-bold text-lg">Dr. Aris Thorne</h4>
|
||||||
|
</div>
|
||||||
|
<div class="flex border-b">
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold text-gray-400 hover:bg-gray-50">Rolle</button>
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold text-gray-400 hover:bg-gray-50">Hinweise</button>
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold text-gray-400 hover:bg-gray-50">Charaktere</button>
|
||||||
|
<button class="flex-1 p-2 text-sm font-semibold border-b-2 border-blue-600 text-blue-600">Zeitstrahl</button>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 flex-grow overflow-y-auto text-sm text-gray-700">
|
||||||
|
<h5 class="font-bold text-base mb-4">Dein persönlicher Zeitstrahl</h5>
|
||||||
|
<div class="relative border-l-2 border-gray-200 space-y-4">
|
||||||
|
<div class="relative pl-6">
|
||||||
|
<div class="absolute -left-[7px] top-1 w-3 h-3 bg-blue-500 rounded-full border-2 border-white"></div>
|
||||||
|
<div class="bg-blue-50 p-2 rounded-lg border border-blue-100">
|
||||||
|
<p class="font-semibold text-xs text-blue-800">16:30 - 16:45 Uhr</p>
|
||||||
|
<p class="text-xs text-blue-900 mt-1">Streitgespräch mit dem Opfer im Labor.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="relative pl-6">
|
||||||
|
<div class="absolute -left-[7px] top-1 w-3 h-3 bg-gray-400 rounded-full border-2 border-white"></div>
|
||||||
|
<div class="bg-gray-50 p-2 rounded-lg border border-gray-200">
|
||||||
|
<p class="font-semibold text-xs text-gray-600">16:45 - 17:00 Uhr</p>
|
||||||
|
<p class="text-xs text-gray-700 mt-1">Alleine im Büro, E-Mails beantwortet.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="relative pl-6">
|
||||||
|
<div class="absolute -left-[7px] top-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white"></div>
|
||||||
|
<div class="bg-green-50 p-2 rounded-lg border border-green-100">
|
||||||
|
<p class="font-semibold text-xs text-green-800">17:00 - 17:20 Uhr</p>
|
||||||
|
<p class="text-xs text-green-900 mt-1">Gespräch mit Ivan Petrov in der Cafeteria. <span class="font-bold">(Dein Alibi)</span></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="relative pl-6">
|
||||||
|
<div class="absolute -left-[7px] top-1 w-3 h-3 bg-red-500 rounded-full ring-2 ring-red-200 border-2 border-white"></div>
|
||||||
|
<div class="bg-red-50 p-2 rounded-lg border border-red-100">
|
||||||
|
<p class="font-semibold text-xs text-red-800">ca. 17:30 Uhr (TODESZEITPUNKT)</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Wireframe 8: Auflösung -->
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg border">
|
||||||
|
<h3 class="text-lg font-semibold mb-3 text-center">8. Auflösung</h3>
|
||||||
|
<div class="bg-white w-full max-w-sm mx-auto aspect-[9/19.5] rounded-2xl shadow-lg p-3 border flex flex-col">
|
||||||
|
<div class="text-center pt-4 pb-3 border-b bg-red-50">
|
||||||
|
<h4 class="font-bold text-lg text-red-700">Der Mörder war...</h4>
|
||||||
|
<p class="text-xl font-bold">Ivan Petrov!</p>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 flex-grow overflow-y-auto text-sm text-gray-700 space-y-3">
|
||||||
|
<p class="text-xs">Sein Motiv war Rache, da das Opfer ihn erpresst hat. Die Mordwaffe war ein schwerer Schraubenschlüssel aus dem Werkzeugraum.</p>
|
||||||
|
<h5 class="font-semibold pt-2">Abstimmungsergebnis</h5>
|
||||||
|
<ul class="text-xs space-y-1">
|
||||||
|
<li>Du hast für <strong>Evelyn Reed</strong> gestimmt.</li>
|
||||||
|
<li>Maria hat für <strong>Ivan Petrov</strong> gestimmt. (Korrekt!)</li>
|
||||||
|
<li>Jonas hat für <strong>Sandra</strong> gestimmt.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 border-t">
|
||||||
|
<button class="w-full bg-blue-600 text-white rounded-md py-2 font-semibold text-sm hover:bg-blue-700">Alle Geschichten lesen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Wireframe 9: Host Dashboard -->
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg border">
|
||||||
|
<h3 class="text-lg font-semibold mb-3 text-center">9. Host Notfall-Dashboard</h3>
|
||||||
|
<div class="bg-white w-full max-w-sm mx-auto aspect-[9/19.5] rounded-2xl shadow-lg p-3 border flex flex-col">
|
||||||
|
<div class="text-center pt-4 pb-3 border-b">
|
||||||
|
<h4 class="font-bold text-lg text-red-600">Host Notfall-Dashboard</h4>
|
||||||
|
<p class="text-xs text-gray-500">Spoiler-freie Steuerung (im Spiel)</p>
|
||||||
|
</div>
|
||||||
|
<div class="px-3 py-4 flex-grow space-y-4">
|
||||||
|
<div>
|
||||||
|
<h5 class="font-semibold mb-2">Spiel-Steuerung</h5>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<button class="w-full bg-yellow-500 text-white rounded-md py-2 text-sm font-semibold hover:bg-yellow-600">Spiel Pausieren</button>
|
||||||
|
<button class="w-full bg-orange-500 text-white rounded-md py-2 text-sm font-semibold hover:bg-orange-600">Nächste Runde erzwingen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h5 class="font-semibold mb-2">Experten-Optionen</h5>
|
||||||
|
<button class="w-full bg-purple-600 text-white rounded-md py-2 text-sm font-semibold hover:bg-purple-700">Hinweise neu generieren</button>
|
||||||
|
<p class="text-xs text-gray-500 mt-1">Achtung: Generiert nur die Hinweise für die AKTUELLE Runde neu. Nur nutzen, wenn Hinweise fehlerhaft wirken.</p>
|
||||||
|
</div>
|
||||||
|
<div class="pt-4">
|
||||||
|
<h5 class="font-semibold mb-2 text-red-700">Gefahrenzone</h5>
|
||||||
|
<button class="w-full bg-red-600 text-white rounded-md py-2 text-sm font-semibold hover:bg-red-700">Spiel komplett neu starten</button>
|
||||||
|
<p class="text-xs text-gray-500 mt-1">Beendet das Spiel für alle und startet die Lobby neu.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="mb-10">
|
||||||
|
<h2 class="text-2xl font-semibold text-gray-800 border-b pb-2 mb-4">5. API-Endpunkte & Datenbank-Interaktion</h2>
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-xl font-semibold mb-3">FastAPI-Backend (erweitert)</h3>
|
||||||
|
<p class="mb-3">Das Backend wird zur zentralen API für die gesamte Spiellogik. Alle Endpunkte erfordern ein gültiges Supabase JWT.</p>
|
||||||
|
<ul class="list-disc list-inside space-y-2 bg-gray-50 p-4 rounded-lg">
|
||||||
|
<li><code>POST /game/create</code>: Erstellt ein neues Spiel, ruft OpenAI auf, speichert in PG_DB.</li>
|
||||||
|
<li><code>POST /game/{game_code}/join</code>: Fügt einen Spieler zu einem Spiel hinzu.</li>
|
||||||
|
<li><code>GET /game/{game_code}/state</code>: Ruft den aktuellen Zustand eines Spiels ab.</li>
|
||||||
|
<li><code>POST /game/{game_code}/vote</code>: Gibt eine Stimme für einen Charakter ab.</li>
|
||||||
|
<li><code>GET /game/{game_code}/character</code>: Ruft die Charakterdetails für den authentifizierten Spieler ab.</li>
|
||||||
|
<li><code>/ws/{game_code}</code>: WebSocket-Endpunkt für Echtzeit-Updates.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-xl font-semibold mb-3">Client-Interaktionen</h3>
|
||||||
|
<ul class="list-disc list-inside space-y-2">
|
||||||
|
<li><strong>Supabase Auth (`supabase-js`):</strong> Wird in der React Native App ausschließlich für Login, Registrierung und die Verwaltung des Auth-Zustands (JWT) verwendet.</li>
|
||||||
|
<li><strong>API-Client (z.B. Axios):</strong> Wird für alle HTTP-Anfragen an das FastAPI-Backend genutzt.</li>
|
||||||
|
<li><strong>WebSocket-Client:</strong> Wird verwendet, um die Echtzeit-Verbindung zum <code>/ws/...</code> Endpunkt des Backends herzustellen und auf Updates zu lauschen.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="mb-10">
|
||||||
|
<h2 class="text-2xl font-semibold text-gray-800 border-b pb-2 mb-4">6. Datenmodelle & `game_data` Detailbeschreibung</h2>
|
||||||
|
<p class="mb-4">Die dedizierte PostgreSQL-Datenbank enthält die gesamte Spiellogik, während Supabase ausschließlich für die Identitätsverwaltung zuständig ist.</p>
|
||||||
|
|
||||||
|
<h3 class="text-xl font-semibold mt-6 mb-3">Dedizierte PostgreSQL-Datenbank (Spieldaten)</h3>
|
||||||
|
<div class="space-y-8">
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<h4 class="font-semibold mb-2 text-lg">Tabelle: `games`</h4>
|
||||||
|
<div class="rounded-lg border">
|
||||||
|
<table class="min-w-full divide-y divide-gray-200">
|
||||||
|
<thead class="bg-gray-50">
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Spalte</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Datentyp</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Beschreibung</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
|
<tr><td class="px-6 py-4">id</td><td class="px-6 py-4">uuid</td><td class="px-6 py-4">Eindeutige ID für ein Spiel.</td></tr>
|
||||||
|
<tr class="bg-gray-50"><td class="px-6 py-4">created_at</td><td class="px-6 py-4">timestamp</td><td class="px-6 py-4">Zeitstempel der Erstellung.</td></tr>
|
||||||
|
<tr><td class="px-6 py-4">host_id</td><td class="px-6 py-4">uuid</td><td class="px-6 py-4">Referenz auf die User-ID des Hosts aus Supabase.</td></tr>
|
||||||
|
<tr class="bg-gray-50"><td class="px-6 py-4">game_code</td><td class="px-6 py-4">varchar</td><td class="px-6 py-4">Kurzer Code zum Beitreten (z.B. "GHY-781"). <strong>Indiziert!</strong></td></tr>
|
||||||
|
<tr><td class="px-6 py-4">status</td><td class="px-6 py-4">varchar</td><td class="px-6 py-4">Aktueller Status (setup, lobby, active, finished).</td></tr>
|
||||||
|
<tr class="bg-gray-50"><td class="px-6 py-4">game_data</td><td class="px-6 py-4">jsonb</td><td class="px-6 py-4">Das komplette KI-generierte Szenario.</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<h4 class="font-semibold mb-2 text-lg mt-6">Tabelle: `players`</h4>
|
||||||
|
<div class="rounded-lg border">
|
||||||
|
<table class="min-w-full divide-y divide-gray-200">
|
||||||
|
<thead class="bg-gray-50">
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Spalte</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Datentyp</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Beschreibung</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
|
<tr><td class="px-6 py-4">id</td><td class="px-6 py-4">uuid</td><td class="px-6 py-4">Eindeutiger Eintrag für einen Spieler in einem Spiel.</td></tr>
|
||||||
|
<tr class="bg-gray-50"><td class="px-6 py-4">game_id</td><td class="px-6 py-4">uuid</td><td class="px-6 py-4">Verweist auf das zugehörige Spiel in `games`.</td></tr>
|
||||||
|
<tr><td class="px-6 py-4">player_id</td><td class="px-6 py-4">uuid</td><td class="px-6 py-4">Referenz auf die User-ID aus Supabase (kann `NULL` sein).</td></tr>
|
||||||
|
<tr class="bg-gray-50"><td class="px-6 py-4">player_name</td><td class="px-6 py-4">varchar</td><td class="px-6 py-4">Der im Spiel angezeigte Name des Spielers.</td></tr>
|
||||||
|
<tr><td class="px-6 py-4">character_id</td><td class="px-6 py-4">varchar</td><td class="px-6 py-4">Verknüpft den Spieler mit seiner Rolle im `game_data`-JSON.</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-blue-50 border-l-4 border-blue-500 text-blue-800 p-4 rounded-lg mt-6">
|
||||||
|
<h3 class="text-xl font-semibold mb-3">Die `game_data` (jsonb) Spalte: Der "digitale Spielkarton"</h3>
|
||||||
|
<p>Diese einzelne Spalte ist das narrative Herzstück jedes Spiels. Hier wird das gesamte, von der KI generierte und validierte JSON-Objekt gespeichert.</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="mb-10">
|
||||||
|
<h2 class="text-2xl font-semibold text-gray-800 border-b pb-2 mb-4">7. Prompt-Engineering-Strategie</h2>
|
||||||
|
<div class="space-y-8 mt-6">
|
||||||
|
<div class="bg-gray-50 p-5 rounded-lg">
|
||||||
|
<h3 class="text-xl font-semibold mb-3">Prompt 1: Der kreative Autor</h3>
|
||||||
|
<h4 class="font-semibold text-gray-700">System-Prompt:</h4>
|
||||||
|
<p class="mb-3 p-3 bg-gray-200 rounded text-sm">Du bist ein preisgekrönter Autor von Kriminalromanen. Deine Aufgabe ist es, ein vollständiges, komplexes und fesselndes Krimi-Dinner-Szenario zu erstellen. Halte dich exakt an die vorgegebene JSON-Struktur.</p>
|
||||||
|
<h4 class="font-semibold text-gray-700">User-Prompt (Beispiel):</h4>
|
||||||
|
<p class="p-3 bg-gray-200 rounded text-sm">Erstelle ein Krimi-Dinner-Szenario für 5 Spieler über 3 Runden. Das Thema lautet: "Ein Mord auf einer Tech-Konferenz im Jahr 2035". Erstelle für jeden Charakter einen lückenlosen Zeitstrahl mit Zeitblöcken (z.B. "16:30-16:45") und verteile die Hinweise logisch auf die Runden. Generiere das vollständige Spiel-JSON und stelle sicher, dass der Mord logisch aufgeklärt werden kann.</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 p-5 rounded-lg">
|
||||||
|
<h3 class="text-xl font-semibold mb-3">Prompt 2: Der Logik-Lektor</h3>
|
||||||
|
<h4 class="font-semibold text-gray-700">System-Prompt:</h4>
|
||||||
|
<p class="mb-3 p-3 bg-gray-200 rounded text-sm">Du bist ein extrem detailorientierter und logisch denkender Lektor. Deine Aufgabe ist es, das dir vorgelegte Krimi-Szenario auf Widersprüche und Logikfehler zu überprüfen und minimalinvasiv zu korrigieren.</p>
|
||||||
|
<h4 class="font-semibold text-gray-700">User-Prompt:</h4>
|
||||||
|
<p class="p-3 bg-gray-200 rounded text-sm">Hier ist ein JSON-Objekt. Bitte agiere als Logik-Lektor. Überprüfe es auf: Zeitlinien-Konflikte (sind die Zeitstrahlen aller Charaktere widerspruchsfrei?), Motiv-Schwäche, Unlösbarkeit, Inkonsistente Charakter-Aktionen. Gib das vollständige, korrigierte JSON zurück.<br><br><em>[Hier wird das gesamte JSON aus Schritt 1 eingefügt]</em></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="mb-10">
|
||||||
|
<h2 class="text-2xl font-semibold text-gray-800 border-b pb-2 mb-4">8. User Journey & Spielablauf</h2>
|
||||||
|
<p>Der Lebenszyklus eines Spiels ist in mehrere Phasen unterteilt, wobei jede Runde einem definierten Zeitfenster entspricht, um den Zeitstrahl zu strukturieren.</p>
|
||||||
|
<ol class="list-decimal list-inside space-y-4">
|
||||||
|
<li><strong>Phase 0: Generierung & Vorbereitung (<code>status: setup</code>)</strong>
|
||||||
|
<p class="text-sm text-gray-600 ml-6">Der Host kann ein Spiel generieren, lange bevor es stattfindet. In dieser Phase erhält er den Einladungscode und eine <strong>spoiler-freie Übersicht</strong> über Thema und Charakter-Namen zur Vorbereitung.</p>
|
||||||
|
</li>
|
||||||
|
<li><strong>Phase 1: Lobby (<code>status: lobby</code>)</strong>
|
||||||
|
<p class="text-sm text-gray-600 ml-6">Am Tag des Spiels öffnet der Host die Lobby. Die Spieler treten mit dem Code bei. Der Host kann Spieler hinzufügen/entfernen und hat die Option, das Szenario neu zu generieren, bevor er das Spiel startet.</p>
|
||||||
|
</li>
|
||||||
|
<li><strong>Phase 2: Rollenverteilung</strong>
|
||||||
|
<p class="text-sm text-gray-600 ml-6">Nach dem Spielstart weist das Backend jedem Spieler eine Rolle zu und sendet die geheimen Informationen an das jeweilige Gerät.</p>
|
||||||
|
</li>
|
||||||
|
<li><strong>Phase 3: Spielrunden (<code>status: active</code>)</strong>
|
||||||
|
<p class="text-sm text-gray-600 ml-6">Das Spiel verläuft in Runden, die jeweils einem Zeitfenster zugeordnet sind (z.B. Runde 1: 16-18 Uhr). In jeder Runde gibt das System neue Hinweise frei. Spieler können ihren persönlichen Zeitstrahl und alle bisherigen Hinweise einsehen.</p>
|
||||||
|
</li>
|
||||||
|
<li><strong>Phase 4: Abstimmung & Auflösung (<code>status: finished</code>)</strong>
|
||||||
|
<p class="text-sm text-gray-600 ml-6">Nach der letzten Runde wird die Abstimmung freigeschaltet. Danach folgt die Auflösung, bei der der Mörder und alle Geheimnisse enthüllt werden.</p>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="mb-10">
|
||||||
|
<h2 class="text-2xl font-semibold text-gray-800 border-b pb-2 mb-4">9. Geschäftsmodell & Monetarisierung</h2>
|
||||||
|
<p>Die App wird kein kostenloses Basis-Modell anbieten. Die Monetarisierung erfolgt direkt über die Nutzung der Spiunktion.</p>
|
||||||
|
<div class="grid md:grid-cols-2 gap-6 mt-6">
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
|
<h3 class="font-semibold text-lg mb-2">Abonnement-Modell</h3>
|
||||||
|
<p class="text-sm">Nutzer zahlen einen monatlichen oder jährlichen Beitrag und erhalten dafür ein festes Kontingent an Spielen (z.B. die Möglichkeit, 2 Spiele pro Woche zu generieren und zu spielen).</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
|
<h3 class="font-semibold text-lg mb-2">Einmalkauf (Pay-per-Game)</h3>
|
||||||
|
<p class="text-sm">Alternativ zum Abo können Nutzer einzelne Spiele per Einmalkauf freischalten. Dies bietet maximale Flexibilität für Gelegenheitsspieler.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="mb-10">
|
||||||
|
<h2 class="text-2xl font-semibold text-gray-800 border-b pb-2 mb-4">10. Skalierbarkeit, Kosten & Fehlerbehandlung</h2>
|
||||||
|
<ul class="list-disc list-inside space-y-3 mt-6">
|
||||||
|
<li><strong>Kostenkontrolle (OpenAI):</strong> Ein <strong>Rate-Limiting</strong> auf dem <code>/game/create</code> Endpunkt verhindert Missbrauch (z.B. nur ein Spiel alle 5 Minuten pro Nutzer).</li>
|
||||||
|
<li><strong>Fehlerbehandlung bei Generierung:</strong> Schlägt der OpenAI-Call fehl, unternimmt das Backend automatisch 1-2 erneute Versuche, bevor es einen Fehler an den Host meldet.</li>
|
||||||
|
<li><strong>Nahtloses Wiederverbinden:</strong> Spieler können jederzeit wieder in ein laufendes Spiel einsteigen (z.B. nach Verbindungsabbruch) und erhalten den aktuellen Spielzustand.</li>
|
||||||
|
<li><strong>Notfall-Dashboard (Host):</strong> Der Host erhält ein simples, spoiler-freies Admin-Panel, um das Spiel zu pausieren, Runden manuell auszulösen oder als Experte die Hinweise einer Runde neu zu generieren. Für katastrophale Fehler gibt es eine Option zum kompletten Neustart des Spiels.</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2 class="text-2xl font-semibold text-gray-800 border-b pb-2 mb-4">11. Rechtliches & Datenschutz</h2>
|
||||||
|
<p class="mt-6">Aufgrund der Verarbeitung von E-Mail-Adressen für die Authentifizierung sind folgende Punkte für den Launch zwingend erforderlich:</p>
|
||||||
|
<ul class="list-disc list-inside space-y-2">
|
||||||
|
<li><strong>DSGVO-konforme Datenschutzerklärung:</strong> Beschreibt, welche Daten zu welchem Zweck verarbeitet werden.</li>
|
||||||
|
<li><strong>Impressum:</strong> Gesetzlich vorgeschriebene Angabe des Betreibers.</li>
|
||||||
|
<li><strong>Löschung des Accounts:</strong> Eine einfache Möglichkeit für Nutzer, ihren Account und alle Daten zu löschen.</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
mermaid.initialize({ startOnLoad: true });
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
694
package-lock.json
generated
694
package-lock.json
generated
@ -13,6 +13,7 @@
|
|||||||
"@testing-library/react": "^16.3.0",
|
"@testing-library/react": "^16.3.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"bootstrap": "^5.3.5",
|
"bootstrap": "^5.3.5",
|
||||||
|
"mermaid": "^10.9.1",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-bootstrap": "^2.10.9",
|
"react-bootstrap": "^2.10.9",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
@ -81,7 +82,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz",
|
||||||
"integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==",
|
"integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ampproject/remapping": "^2.2.0",
|
"@ampproject/remapping": "^2.2.0",
|
||||||
"@babel/code-frame": "^7.26.2",
|
"@babel/code-frame": "^7.26.2",
|
||||||
@ -722,7 +722,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz",
|
||||||
"integrity": "sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==",
|
"integrity": "sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.25.9"
|
"@babel/helper-plugin-utils": "^7.25.9"
|
||||||
},
|
},
|
||||||
@ -1587,7 +1586,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz",
|
||||||
"integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==",
|
"integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-annotate-as-pure": "^7.25.9",
|
"@babel/helper-annotate-as-pure": "^7.25.9",
|
||||||
"@babel/helper-module-imports": "^7.25.9",
|
"@babel/helper-module-imports": "^7.25.9",
|
||||||
@ -2075,6 +2073,12 @@
|
|||||||
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
|
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@braintree/sanitize-url": {
|
||||||
|
"version": "6.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz",
|
||||||
|
"integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@csstools/normalize.css": {
|
"node_modules/@csstools/normalize.css": {
|
||||||
"version": "12.1.1",
|
"version": "12.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.1.1.tgz",
|
||||||
@ -3102,7 +3106,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
"url": "https://opencollective.com/popperjs"
|
"url": "https://opencollective.com/popperjs"
|
||||||
@ -3539,7 +3542,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
|
||||||
"integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
|
"integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.10.4",
|
"@babel/code-frame": "^7.10.4",
|
||||||
"@babel/runtime": "^7.12.5",
|
"@babel/runtime": "^7.12.5",
|
||||||
@ -3748,6 +3750,27 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/d3-scale": {
|
||||||
|
"version": "4.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
|
||||||
|
"integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/d3-time": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-scale-chromatic": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-time": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/debug": {
|
"node_modules/@types/debug": {
|
||||||
"version": "4.1.12",
|
"version": "4.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
|
||||||
@ -3974,7 +3997,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz",
|
||||||
"integrity": "sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==",
|
"integrity": "sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
@ -4101,7 +4123,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
|
||||||
"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
|
"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.4.0",
|
"@eslint-community/regexpp": "^4.4.0",
|
||||||
"@typescript-eslint/scope-manager": "5.62.0",
|
"@typescript-eslint/scope-manager": "5.62.0",
|
||||||
@ -4155,7 +4176,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
|
||||||
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
|
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "5.62.0",
|
"@typescript-eslint/scope-manager": "5.62.0",
|
||||||
"@typescript-eslint/types": "5.62.0",
|
"@typescript-eslint/types": "5.62.0",
|
||||||
@ -4525,7 +4545,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
||||||
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
|
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@ -4612,7 +4631,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.1",
|
"fast-deep-equal": "^3.1.1",
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
@ -5529,7 +5547,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"caniuse-lite": "^1.0.30001688",
|
"caniuse-lite": "^1.0.30001688",
|
||||||
"electron-to-chromium": "^1.5.73",
|
"electron-to-chromium": "^1.5.73",
|
||||||
@ -6208,6 +6225,15 @@
|
|||||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/cose-base": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"layout-base": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cosmiconfig": {
|
"node_modules/cosmiconfig": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
|
||||||
@ -6628,6 +6654,487 @@
|
|||||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/cytoscape": {
|
||||||
|
"version": "3.33.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz",
|
||||||
|
"integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cytoscape-cose-bilkent": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"cose-base": "^1.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"cytoscape": "^3.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3": {
|
||||||
|
"version": "7.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz",
|
||||||
|
"integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-array": "3",
|
||||||
|
"d3-axis": "3",
|
||||||
|
"d3-brush": "3",
|
||||||
|
"d3-chord": "3",
|
||||||
|
"d3-color": "3",
|
||||||
|
"d3-contour": "4",
|
||||||
|
"d3-delaunay": "6",
|
||||||
|
"d3-dispatch": "3",
|
||||||
|
"d3-drag": "3",
|
||||||
|
"d3-dsv": "3",
|
||||||
|
"d3-ease": "3",
|
||||||
|
"d3-fetch": "3",
|
||||||
|
"d3-force": "3",
|
||||||
|
"d3-format": "3",
|
||||||
|
"d3-geo": "3",
|
||||||
|
"d3-hierarchy": "3",
|
||||||
|
"d3-interpolate": "3",
|
||||||
|
"d3-path": "3",
|
||||||
|
"d3-polygon": "3",
|
||||||
|
"d3-quadtree": "3",
|
||||||
|
"d3-random": "3",
|
||||||
|
"d3-scale": "4",
|
||||||
|
"d3-scale-chromatic": "3",
|
||||||
|
"d3-selection": "3",
|
||||||
|
"d3-shape": "3",
|
||||||
|
"d3-time": "3",
|
||||||
|
"d3-time-format": "4",
|
||||||
|
"d3-timer": "3",
|
||||||
|
"d3-transition": "3",
|
||||||
|
"d3-zoom": "3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-array": {
|
||||||
|
"version": "3.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
|
||||||
|
"integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"internmap": "1 - 2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-axis": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-brush": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-dispatch": "1 - 3",
|
||||||
|
"d3-drag": "2 - 3",
|
||||||
|
"d3-interpolate": "1 - 3",
|
||||||
|
"d3-selection": "3",
|
||||||
|
"d3-transition": "3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-chord": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-path": "1 - 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-color": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-contour": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-array": "^3.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-delaunay": {
|
||||||
|
"version": "6.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
|
||||||
|
"integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"delaunator": "5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-dispatch": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-drag": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-dispatch": "1 - 3",
|
||||||
|
"d3-selection": "3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-dsv": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "7",
|
||||||
|
"iconv-lite": "0.6",
|
||||||
|
"rw": "1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"csv2json": "bin/dsv2json.js",
|
||||||
|
"csv2tsv": "bin/dsv2dsv.js",
|
||||||
|
"dsv2dsv": "bin/dsv2dsv.js",
|
||||||
|
"dsv2json": "bin/dsv2json.js",
|
||||||
|
"json2csv": "bin/json2dsv.js",
|
||||||
|
"json2dsv": "bin/json2dsv.js",
|
||||||
|
"json2tsv": "bin/json2dsv.js",
|
||||||
|
"tsv2csv": "bin/dsv2dsv.js",
|
||||||
|
"tsv2json": "bin/dsv2json.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-dsv/node_modules/commander": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-ease": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-fetch": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-dsv": "1 - 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-force": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-dispatch": "1 - 3",
|
||||||
|
"d3-quadtree": "1 - 3",
|
||||||
|
"d3-timer": "1 - 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-format": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-geo": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-array": "2.5.0 - 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-hierarchy": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-interpolate": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-color": "1 - 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-path": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-polygon": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-quadtree": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-random": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-sankey": {
|
||||||
|
"version": "0.12.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz",
|
||||||
|
"integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-array": "1 - 2",
|
||||||
|
"d3-shape": "^1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-sankey/node_modules/d3-array": {
|
||||||
|
"version": "2.12.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
|
||||||
|
"integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"internmap": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-sankey/node_modules/d3-path": {
|
||||||
|
"version": "1.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
|
||||||
|
"integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/d3-sankey/node_modules/d3-shape": {
|
||||||
|
"version": "1.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz",
|
||||||
|
"integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-path": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-sankey/node_modules/internmap": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/d3-scale": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-array": "2.10.0 - 3",
|
||||||
|
"d3-format": "1 - 3",
|
||||||
|
"d3-interpolate": "1.2.0 - 3",
|
||||||
|
"d3-time": "2.1.1 - 3",
|
||||||
|
"d3-time-format": "2 - 4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-scale-chromatic": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-color": "1 - 3",
|
||||||
|
"d3-interpolate": "1 - 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-selection": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-shape": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-path": "^3.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-time": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-array": "2 - 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-time-format": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-time": "1 - 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-timer": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-transition": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-color": "1 - 3",
|
||||||
|
"d3-dispatch": "1 - 3",
|
||||||
|
"d3-ease": "1 - 3",
|
||||||
|
"d3-interpolate": "1 - 3",
|
||||||
|
"d3-timer": "1 - 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"d3-selection": "2 - 3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-zoom": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-dispatch": "1 - 3",
|
||||||
|
"d3-drag": "2 - 3",
|
||||||
|
"d3-interpolate": "1 - 3",
|
||||||
|
"d3-selection": "2 - 3",
|
||||||
|
"d3-transition": "2 - 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dagre-d3-es": {
|
||||||
|
"version": "7.0.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.13.tgz",
|
||||||
|
"integrity": "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"d3": "^7.9.0",
|
||||||
|
"lodash-es": "^4.17.21"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/damerau-levenshtein": {
|
"node_modules/damerau-levenshtein": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
||||||
@ -6699,6 +7206,12 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dayjs": {
|
||||||
|
"version": "1.11.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
|
||||||
|
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||||
@ -6821,6 +7334,15 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/delaunator": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"robust-predicates": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/delayed-stream": {
|
"node_modules/delayed-stream": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
@ -7059,6 +7581,15 @@
|
|||||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dompurify": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==",
|
||||||
|
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@types/trusted-types": "^2.0.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/domutils": {
|
"node_modules/domutils": {
|
||||||
"version": "2.8.0",
|
"version": "2.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
|
||||||
@ -7151,6 +7682,12 @@
|
|||||||
"integrity": "sha512-FWlQc52z1dXqm+9cCJ2uyFgJkESd+16j6dBEjsgDNuHjBpuIzL8/lRc0uvh1k8RNI6waGo6tcy2DvwkTBJOLDg==",
|
"integrity": "sha512-FWlQc52z1dXqm+9cCJ2uyFgJkESd+16j6dBEjsgDNuHjBpuIzL8/lRc0uvh1k8RNI6waGo6tcy2DvwkTBJOLDg==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/elkjs": {
|
||||||
|
"version": "0.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.3.tgz",
|
||||||
|
"integrity": "sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==",
|
||||||
|
"license": "EPL-2.0"
|
||||||
|
},
|
||||||
"node_modules/emittery": {
|
"node_modules/emittery": {
|
||||||
"version": "0.8.1",
|
"version": "0.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz",
|
||||||
@ -7469,7 +8006,6 @@
|
|||||||
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
|
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
|
||||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.6.1",
|
"@eslint-community/regexpp": "^4.6.1",
|
||||||
@ -9693,6 +10229,15 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/internmap": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/invariant": {
|
"node_modules/invariant": {
|
||||||
"version": "2.2.4",
|
"version": "2.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||||
@ -10439,7 +10984,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz",
|
||||||
"integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==",
|
"integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jest/core": "^27.5.1",
|
"@jest/core": "^27.5.1",
|
||||||
"import-local": "^3.0.2",
|
"import-local": "^3.0.2",
|
||||||
@ -11519,6 +12063,22 @@
|
|||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/katex": {
|
||||||
|
"version": "0.16.25",
|
||||||
|
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.25.tgz",
|
||||||
|
"integrity": "sha512-woHRUZ/iF23GBP1dkDQMh1QBad9dmr8/PAwNA54VrSOVYgI12MAcE14TqnDdQOdzyEonGzMepYnqBMYdsoAr8Q==",
|
||||||
|
"funding": [
|
||||||
|
"https://opencollective.com/katex",
|
||||||
|
"https://github.com/sponsors/katex"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "^8.3.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"katex": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/keyv": {
|
"node_modules/keyv": {
|
||||||
"version": "4.5.4",
|
"version": "4.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||||
@ -11528,6 +12088,11 @@
|
|||||||
"json-buffer": "3.0.1"
|
"json-buffer": "3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/khroma": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw=="
|
||||||
|
},
|
||||||
"node_modules/kind-of": {
|
"node_modules/kind-of": {
|
||||||
"version": "6.0.3",
|
"version": "6.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||||
@ -11583,6 +12148,12 @@
|
|||||||
"shell-quote": "^1.8.1"
|
"shell-quote": "^1.8.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/layout-base": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/leven": {
|
"node_modules/leven": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||||
@ -11661,6 +12232,12 @@
|
|||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash-es": {
|
||||||
|
"version": "4.17.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||||
|
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/lodash.debounce": {
|
"node_modules/lodash.debounce": {
|
||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||||
@ -12094,6 +12671,47 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mermaid": {
|
||||||
|
"version": "10.9.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-10.9.5.tgz",
|
||||||
|
"integrity": "sha512-eRlKEjzak4z1rcXeCd1OAlyawhrptClQDo8OuI8n6bSVqJ9oMfd5Lrf3Q+TdJHewi/9AIOc3UmEo8Fz+kNzzuQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@braintree/sanitize-url": "^6.0.1",
|
||||||
|
"@types/d3-scale": "^4.0.3",
|
||||||
|
"@types/d3-scale-chromatic": "^3.0.0",
|
||||||
|
"cytoscape": "^3.28.1",
|
||||||
|
"cytoscape-cose-bilkent": "^4.1.0",
|
||||||
|
"d3": "^7.4.0",
|
||||||
|
"d3-sankey": "^0.12.3",
|
||||||
|
"dagre-d3-es": "7.0.13",
|
||||||
|
"dayjs": "^1.11.7",
|
||||||
|
"dompurify": "^3.2.4",
|
||||||
|
"elkjs": "^0.9.0",
|
||||||
|
"katex": "^0.16.9",
|
||||||
|
"khroma": "^2.0.0",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
|
"mdast-util-from-markdown": "^1.3.0",
|
||||||
|
"non-layered-tidy-tree-layout": "^2.0.2",
|
||||||
|
"stylis": "^4.1.3",
|
||||||
|
"ts-dedent": "^2.2.0",
|
||||||
|
"uuid": "^9.0.0",
|
||||||
|
"web-worker": "^1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mermaid/node_modules/uuid": {
|
||||||
|
"version": "9.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||||
|
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa",
|
||||||
|
"https://github.com/sponsors/ctavan"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/methods": {
|
"node_modules/methods": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||||
@ -12913,6 +13531,12 @@
|
|||||||
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
|
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/non-layered-tidy-tree-layout": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/normalize-path": {
|
"node_modules/normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||||
@ -13568,7 +14192,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.8",
|
"nanoid": "^3.3.8",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
@ -14756,7 +15379,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
|
||||||
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
|
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cssesc": "^3.0.0",
|
"cssesc": "^3.0.0",
|
||||||
"util-deprecate": "^1.0.2"
|
"util-deprecate": "^1.0.2"
|
||||||
@ -15154,7 +15776,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
||||||
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
|
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -15323,7 +15944,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
||||||
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.26.0"
|
"scheduler": "^0.26.0"
|
||||||
},
|
},
|
||||||
@ -15402,7 +16022,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
|
||||||
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==",
|
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -16017,12 +16636,17 @@
|
|||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/robust-predicates": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==",
|
||||||
|
"license": "Unlicense"
|
||||||
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "2.79.2",
|
"version": "2.79.2",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
|
||||||
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
|
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"rollup": "dist/bin/rollup"
|
"rollup": "dist/bin/rollup"
|
||||||
},
|
},
|
||||||
@ -16095,6 +16719,12 @@
|
|||||||
"queue-microtask": "^1.2.2"
|
"queue-microtask": "^1.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/rw": {
|
||||||
|
"version": "1.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
|
||||||
|
"integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
"node_modules/sade": {
|
"node_modules/sade": {
|
||||||
"version": "1.8.1",
|
"version": "1.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
|
||||||
@ -16277,7 +16907,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"fast-uri": "^3.0.1",
|
"fast-uri": "^3.0.1",
|
||||||
@ -17250,6 +17879,12 @@
|
|||||||
"postcss": "^8.2.15"
|
"postcss": "^8.2.15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/stylis": {
|
||||||
|
"version": "4.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz",
|
||||||
|
"integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/sucrase": {
|
"node_modules/sucrase": {
|
||||||
"version": "3.35.0",
|
"version": "3.35.0",
|
||||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
|
||||||
@ -17845,6 +18480,15 @@
|
|||||||
"integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==",
|
"integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/ts-dedent": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ts-interface-checker": {
|
"node_modules/ts-interface-checker": {
|
||||||
"version": "0.1.13",
|
"version": "0.1.13",
|
||||||
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
|
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
|
||||||
@ -17943,7 +18587,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
|
||||||
"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
|
"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
|
||||||
"license": "(MIT OR CC0-1.0)",
|
"license": "(MIT OR CC0-1.0)",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
@ -18549,6 +19192,12 @@
|
|||||||
"integrity": "sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg==",
|
"integrity": "sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg==",
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
|
"node_modules/web-worker": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/webidl-conversions": {
|
"node_modules/webidl-conversions": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
|
||||||
@ -18563,7 +19212,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.6.tgz",
|
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.6.tgz",
|
||||||
"integrity": "sha512-TJOLrJ6oeccsGWPl7ujCYuc0pIq2cNsuD6GZDma8i5o5Npvcco/z+NKvZSFsP0/x6SShVb0+X2JK/JHUjKY9dQ==",
|
"integrity": "sha512-TJOLrJ6oeccsGWPl7ujCYuc0pIq2cNsuD6GZDma8i5o5Npvcco/z+NKvZSFsP0/x6SShVb0+X2JK/JHUjKY9dQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/eslint-scope": "^3.7.7",
|
"@types/eslint-scope": "^3.7.7",
|
||||||
"@types/estree": "^1.0.6",
|
"@types/estree": "^1.0.6",
|
||||||
@ -18633,7 +19281,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz",
|
||||||
"integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==",
|
"integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/bonjour": "^3.5.9",
|
"@types/bonjour": "^3.5.9",
|
||||||
"@types/connect-history-api-fallback": "^1.3.5",
|
"@types/connect-history-api-fallback": "^1.3.5",
|
||||||
@ -19046,7 +19693,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"fast-uri": "^3.0.1",
|
"fast-uri": "^3.0.1",
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
"react-bootstrap": "^2.10.9",
|
"react-bootstrap": "^2.10.9",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-jupyter-notebook-viewer": "^1.1.13",
|
"react-jupyter-notebook-viewer": "^1.1.13",
|
||||||
|
"mermaid": "^10.9.1",
|
||||||
"react-router-dom": "^7.5.2",
|
"react-router-dom": "^7.5.2",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
|
|||||||
@ -12,11 +12,13 @@ import ServerPage from "./projects/server";
|
|||||||
import LanguagestudyPage from "./projects/languageStudy";
|
import LanguagestudyPage from "./projects/languageStudy";
|
||||||
import OnlineCasinoPage from "./finalprojects/onlineCasino";
|
import OnlineCasinoPage from "./finalprojects/onlineCasino";
|
||||||
import WohnungUndFahrgemeinschaftenPage from "./finalprojects/wohnungUndFahrgemeinschaften";
|
import WohnungUndFahrgemeinschaftenPage from "./finalprojects/wohnungUndFahrgemeinschaften";
|
||||||
|
import KrimiDinnerPage from "./finalprojects/krimiDinner";
|
||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
return <HomePage />;
|
return <HomePage />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function About() {
|
function About() {
|
||||||
return <AboutPage />;
|
return <AboutPage />;
|
||||||
}
|
}
|
||||||
@ -52,6 +54,11 @@ function OnlineCasino() {
|
|||||||
function WohnungUndFahrgemeinschaften() {
|
function WohnungUndFahrgemeinschaften() {
|
||||||
return <WohnungUndFahrgemeinschaftenPage />
|
return <WohnungUndFahrgemeinschaftenPage />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function KrimiDinner() {
|
||||||
|
return <KrimiDinnerPage />
|
||||||
|
}
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
@ -68,6 +75,7 @@ function App() {
|
|||||||
<Route path="/projects/server" element={<Server />} />
|
<Route path="/projects/server" element={<Server />} />
|
||||||
<Route path="/finalprojects/onlineCasino" element={<OnlineCasino />} />
|
<Route path="/finalprojects/onlineCasino" element={<OnlineCasino />} />
|
||||||
<Route path="/finalprojects/wufg" element={<WohnungUndFahrgemeinschaften />} />
|
<Route path="/finalprojects/wufg" element={<WohnungUndFahrgemeinschaften />} />
|
||||||
|
<Route path="/finalprojects/krimidinner" element={<KrimiDinner />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
<FooterSection />
|
<FooterSection />
|
||||||
|
|||||||
307
src/components/finalprojects/krimiDinner.jsx
Normal file
307
src/components/finalprojects/krimiDinner.jsx
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { Container, Row, Col, Card, Badge, Table } from "react-bootstrap";
|
||||||
|
import mermaid from "mermaid";
|
||||||
|
|
||||||
|
function KrimiDinner() {
|
||||||
|
useEffect(() => {
|
||||||
|
mermaid.initialize({ startOnLoad: false, theme: 'neutral' });
|
||||||
|
mermaid.contentLoaded();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="project-page">
|
||||||
|
<Container>
|
||||||
|
<header className="text-center border-b pb-4 mb-5">
|
||||||
|
<h1 className="project-title">Projekt-Blaupause: KI-Krimi-Dinner "Projekt Chimera"</h1>
|
||||||
|
<div className="mt-4 d-flex justify-content-center flex-wrap">
|
||||||
|
<div className="project-meta-item">
|
||||||
|
<Badge bg="secondary" className="text-uppercase">Version</Badge>
|
||||||
|
<span className="meta-value">3.0 (Final & Complete UI)</span>
|
||||||
|
</div>
|
||||||
|
<div className="project-meta-item">
|
||||||
|
<Badge bg="secondary" className="text-uppercase">Autor</Badge>
|
||||||
|
<span className="meta-value">D. Schuhbaum & S. Altschäffl</span>
|
||||||
|
</div>
|
||||||
|
<div className="project-meta-item">
|
||||||
|
<Badge bg="secondary" className="text-uppercase">Datum</Badge>
|
||||||
|
<span className="meta-value">03.10.2025</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section className="mb-5">
|
||||||
|
<h2>1. Projektübersicht</h2>
|
||||||
|
<p>
|
||||||
|
"Projekt Chimera" ist ein hybrides Krimi-Dinner-Erlebnis, das
|
||||||
|
physische soziale Interaktion mit einer digitalen App-Komponente
|
||||||
|
verbindet. Das Alleinstellungsmerkmal ist der Einsatz einer
|
||||||
|
zweistufigen KI-Architektur, die nicht nur einzigartige narrative
|
||||||
|
Szenarien generiert, sondern diese auch proaktiv auf logische
|
||||||
|
Konsistenz validiert und korrigiert.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Die Architektur basiert auf einer klaren Trennung:{" "}
|
||||||
|
<strong>Supabase</strong> dient als dedizierter Service für die
|
||||||
|
Benutzerauthentifizierung, während alle Spieldaten (Szenarien,
|
||||||
|
Spieler, Spielstände) in einer{" "}
|
||||||
|
<strong>separaten, dedizierten PostgreSQL-Datenbank</strong>{" "}
|
||||||
|
gehostet werden. Ein zentrales <strong>FastAPI-Backend</strong>{" "}
|
||||||
|
fungiert als sichere Schnittstelle zwischen den Clients und
|
||||||
|
beiden Diensten.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-5">
|
||||||
|
<h2>2. Narratives Design & Validierung</h2>
|
||||||
|
<p>
|
||||||
|
Die Generierung jedes Spiels folgt einem strengen, zweistufigen
|
||||||
|
Prozess, um die narrative Qualität und logische Integrität zu
|
||||||
|
gewährleisten.
|
||||||
|
</p>
|
||||||
|
<Row className="mt-4">
|
||||||
|
<Col md={6}>
|
||||||
|
<Card className="h-100">
|
||||||
|
<Card.Body>
|
||||||
|
<Card.Title as="h3">Schritt 1: Kreative Generierung (Der "Autor")</Card.Title>
|
||||||
|
<Card.Text>
|
||||||
|
In dieser Phase agiert die KI als kreativer Autor. Sie erhält einen umfassenden Prompt, der die gewünschten Rahmenbedingungen vorgibt.
|
||||||
|
</Card.Text>
|
||||||
|
<ul>
|
||||||
|
<li>Hintergrundgeschichte</li>
|
||||||
|
<li>Charaktere</li>
|
||||||
|
<li>Geheimnisse & Ziele</li>
|
||||||
|
<li>Der Mord & lückenloser Zeitstrahl</li>
|
||||||
|
<li>Beziehungsgeflecht</li>
|
||||||
|
<li>Hinweise</li>
|
||||||
|
</ul>
|
||||||
|
</Card.Body>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
<Col md={6}>
|
||||||
|
<Card className="h-100">
|
||||||
|
<Card.Body>
|
||||||
|
<Card.Title as="h3">Schritt 2: Logische Validierung & Korrektur (Der "Logik-Lektor")</Card.Title>
|
||||||
|
<Card.Text>
|
||||||
|
Der rohe Output wird an eine zweite KI-Instanz übergeben, die als akribischer Logik-Lektor agiert und das Szenario auf Fehler überprüft.
|
||||||
|
</Card.Text>
|
||||||
|
<ul>
|
||||||
|
<li>Widersprüche in Zeitlinien</li>
|
||||||
|
<li>Motiv-Konsistenz</li>
|
||||||
|
<li>Hinweis-Validität</li>
|
||||||
|
<li>Charakter-Konsistenz</li>
|
||||||
|
<li>Regelkonformität</li>
|
||||||
|
</ul>
|
||||||
|
</Card.Body>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-5">
|
||||||
|
<h2>3. Technische Architektur</h2>
|
||||||
|
<p>
|
||||||
|
Die Architektur ist auf maximale Kontrolle und Skalierbarkeit ausgelegt. Die React Native-Clients kommunizieren ausschließlich mit dem FastAPI-Backend. Echtzeit-Updates werden über eine WebSocket-Verbindung gepusht.
|
||||||
|
</p>
|
||||||
|
<div className="text-center bg-light p-3 rounded">
|
||||||
|
<pre className="mermaid">
|
||||||
|
{`
|
||||||
|
graph TD
|
||||||
|
subgraph "Spieler-Geräte"
|
||||||
|
P1["React Native Apps"]
|
||||||
|
end
|
||||||
|
subgraph "Authentifizierung"
|
||||||
|
Auth["Supabase Auth"]
|
||||||
|
end
|
||||||
|
subgraph "Sicheres Backend"
|
||||||
|
FastAPI["FastAPI Server <br> REST & WebSockets"]
|
||||||
|
end
|
||||||
|
subgraph "Spieldaten-Bank"
|
||||||
|
PG_DB["PostgreSQL DB"]
|
||||||
|
end
|
||||||
|
subgraph "Externe Dienste"
|
||||||
|
OAI["OpenAI API"]
|
||||||
|
end
|
||||||
|
P1 -- "1. Login" --> Auth
|
||||||
|
P1 -- "2. API Calls (mit Token)" --> FastAPI
|
||||||
|
FastAPI -- "3. KI Call" --> OAI
|
||||||
|
FastAPI -- "4. DB-Zugriff" --> PG_DB
|
||||||
|
FastAPI -- "5. WebSocket Updates" --> P1
|
||||||
|
`}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
<h3 className="mt-4">Datenfluss-Beschreibung:</h3>
|
||||||
|
<ol>
|
||||||
|
<li><strong>Authentifizierung:</strong> Benutzer authentifiziert sich bei Supabase Auth und erhält ein JWT.</li>
|
||||||
|
<li><strong>API-Anfragen:</strong> Die App sendet Anfragen mit dem JWT an den FastAPI-Server.</li>
|
||||||
|
<li><strong>KI-Generierung:</strong> FastAPI ruft die OpenAI-API für die Spielerstellung auf.</li>
|
||||||
|
<li><strong>Datenbank-Interaktion:</strong> FastAPI ist die einzige Komponente, die mit der PostgreSQL-DB kommuniziert.</li>
|
||||||
|
<li><strong>Echtzeit-Updates:</strong> Clients bauen eine WebSocket-Verbindung zum FastAPI-Server auf.</li>
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-5">
|
||||||
|
<h2>4. User Interface (UI) Konzept</h2>
|
||||||
|
<p>Die UI-Konzepte werden als klare, moderne Wireframes visualisiert, um den gesamten App-Flow darzustellen.</p>
|
||||||
|
<Row>
|
||||||
|
{[
|
||||||
|
{title: "1. Login", content: "Standard-Login-Formular mit E-Mail und Passwort."},
|
||||||
|
{title: "2. Registrierung", content: "Formular zur Erstellung eines neuen Kontos."},
|
||||||
|
{title: "3. Home Dashboard", content: "Übersicht der Spiele des Nutzers und Optionen, ein neues Spiel zu starten oder einem beizutreten."},
|
||||||
|
{title: "4. Spiel erstellen", content: "Formular zur Definition des Szenarios und der Rundenanzahl."},
|
||||||
|
{title: "5. Host-Lobby", content: "Anzeige des Spiel-Codes und der beigetretenen Spieler."},
|
||||||
|
{title: "6. Spieler-Ansicht (Rolle)", content: "Anzeige der zugewiesenen Rolle, Ziele und Geheimnisse."},
|
||||||
|
{title: "7. Spieler-Ansicht (Hinweise)", content: "Darstellung der pro Runde freigeschalteten Hinweise."},
|
||||||
|
{title: "8. Auflösung", content: "Enthüllung des Mörders und des Abstimmungsergebnisses."},
|
||||||
|
{title: "9. Host Notfall-Dashboard", content: "Steuerungselemente für den Host, um das Spiel zu managen."}
|
||||||
|
].map(item => (
|
||||||
|
<Col md={4} className="mb-4" key={item.title}>
|
||||||
|
<Card>
|
||||||
|
<Card.Header as="h5" className="text-center">{item.title}</Card.Header>
|
||||||
|
<Card.Body>
|
||||||
|
<Card.Text>{item.content}</Card.Text>
|
||||||
|
</Card.Body>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
))}
|
||||||
|
</Row>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-5">
|
||||||
|
<h2>5. API-Endpunkte & Datenbank-Interaktion</h2>
|
||||||
|
<Row>
|
||||||
|
<Col md={6}>
|
||||||
|
<h3>FastAPI-Backend</h3>
|
||||||
|
<ul className="list-group">
|
||||||
|
<li className="list-group-item"><code>POST /game/create</code></li>
|
||||||
|
<li className="list-group-item"><code>POST /game/{'{game_code}'}/join</code></li>
|
||||||
|
<li className="list-group-item"><code>GET /game/{'{game_code}'}/state</code></li>
|
||||||
|
<li className="list-group-item"><code>POST /game/{'{game_code}'}/vote</code></li>
|
||||||
|
<li className="list-group-item"><code>GET /game/{'{game_code}'}/character</code></li>
|
||||||
|
<li className="list-group-item"><code>/ws/{'{game_code}'}</code></li>
|
||||||
|
</ul>
|
||||||
|
</Col>
|
||||||
|
<Col md={6}>
|
||||||
|
<h3>Client-Interaktionen</h3>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Supabase Auth (`supabase-js`):</strong> Nur für Login, Registrierung und Auth-Zustand.</li>
|
||||||
|
<li><strong>API-Client (z.B. Axios):</strong> Für alle HTTP-Anfragen an das FastAPI-Backend.</li>
|
||||||
|
<li><strong>WebSocket-Client:</strong> Für Echtzeit-Verbindung zum Backend.</li>
|
||||||
|
</ul>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-5">
|
||||||
|
<h2>6. Datenmodelle</h2>
|
||||||
|
<p>Die dedizierte PostgreSQL-Datenbank enthält die gesamte Spiellogik.</p>
|
||||||
|
<h3 className="mt-4">Tabelle: `games`</h3>
|
||||||
|
<Table striped bordered hover responsive>
|
||||||
|
<thead>
|
||||||
|
<tr><th>Spalte</th><th>Datentyp</th><th>Beschreibung</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>id</td><td>uuid</td><td>Eindeutige ID für ein Spiel.</td></tr>
|
||||||
|
<tr><td>host_id</td><td>uuid</td><td>Referenz auf die User-ID des Hosts.</td></tr>
|
||||||
|
<tr><td>game_code</td><td>varchar</td><td>Kurzer Code zum Beitreten.</td></tr>
|
||||||
|
<tr><td>status</td><td>varchar</td><td>setup, lobby, active, finished.</td></tr>
|
||||||
|
<tr><td>game_data</td><td>jsonb</td><td>Das komplette KI-generierte Szenario.</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</Table>
|
||||||
|
|
||||||
|
<h3 className="mt-4">Tabelle: `players`</h3>
|
||||||
|
<Table striped bordered hover responsive>
|
||||||
|
<thead>
|
||||||
|
<tr><th>Spalte</th><th>Datentyp</th><th>Beschreibung</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>id</td><td>uuid</td><td>Eindeutiger Eintrag für einen Spieler.</td></tr>
|
||||||
|
<tr><td>game_id</td><td>uuid</td><td>Verweist auf das zugehörige Spiel.</td></tr>
|
||||||
|
<tr><td>player_id</td><td>uuid</td><td>Referenz auf die User-ID aus Supabase.</td></tr>
|
||||||
|
<tr><td>player_name</td><td>varchar</td><td>Der im Spiel angezeigte Name.</td></tr>
|
||||||
|
<tr><td>character_id</td><td>varchar</td><td>Verknüpft den Spieler mit seiner Rolle.</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</Table>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-5">
|
||||||
|
<h2>7. Prompt-Engineering-Strategie</h2>
|
||||||
|
<Row>
|
||||||
|
<Col md={6}>
|
||||||
|
<Card className="h-100">
|
||||||
|
<Card.Body>
|
||||||
|
<Card.Title>Prompt 1: Der kreative Autor</Card.Title>
|
||||||
|
<Card.Subtitle className="mb-2 text-muted">System-Prompt:</Card.Subtitle>
|
||||||
|
<Card.Text as="div"><pre className="prompt-box">Du bist ein preisgekrönter Autor von Kriminalromanen...</pre></Card.Text>
|
||||||
|
<Card.Subtitle className="mb-2 mt-3 text-muted">User-Prompt:</Card.Subtitle>
|
||||||
|
<Card.Text as="div"><pre className="prompt-box">Erstelle ein Krimi-Dinner-Szenario für 5 Spieler...</pre></Card.Text>
|
||||||
|
</Card.Body>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
<Col md={6}>
|
||||||
|
<Card className="h-100">
|
||||||
|
<Card.Body>
|
||||||
|
<Card.Title>Prompt 2: Der Logik-Lektor</Card.Title>
|
||||||
|
<Card.Subtitle className="mb-2 text-muted">System-Prompt:</Card.Subtitle>
|
||||||
|
<Card.Text as="div"><pre className="prompt-box">Du bist ein extrem detailorientierter und logisch denkender Lektor...</pre></Card.Text>
|
||||||
|
<Card.Subtitle className="mb-2 mt-3 text-muted">User-Prompt:</Card.Subtitle>
|
||||||
|
<Card.Text as="div"><pre className="prompt-box">Hier ist ein JSON-Objekt. Bitte agiere als Logik-Lektor...</pre></Card.Text>
|
||||||
|
</Card.Body>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-5">
|
||||||
|
<h2>8. User Journey & Spielablauf</h2>
|
||||||
|
<ol>
|
||||||
|
<li><strong>Phase 0: Generierung & Vorbereitung:</strong> Host generiert Spiel und erhält Einladungscode.</li>
|
||||||
|
<li><strong>Phase 1: Lobby:</strong> Spieler treten bei, Host startet das Spiel.</li>
|
||||||
|
<li><strong>Phase 2: Rollenverteilung:</strong> Backend weist Rollen zu und sendet geheime Infos.</li>
|
||||||
|
<li><strong>Phase 3: Spielrunden:</strong> System gibt pro Runde neue Hinweise frei.</li>
|
||||||
|
<li><strong>Phase 4: Abstimmung & Auflösung:</strong> Abstimmung wird freigeschaltet, Mörder wird enthüllt.</li>
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-5">
|
||||||
|
<h2>9. Geschäftsmodell & Monetarisierung</h2>
|
||||||
|
<Row>
|
||||||
|
<Col md={6}>
|
||||||
|
<div className="p-3 bg-light rounded h-100">
|
||||||
|
<h3>Abonnement-Modell</h3>
|
||||||
|
<p>Nutzer zahlen einen monatlichen oder jährlichen Beitrag für ein festes Kontingent an Spielen.</p>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col md={6}>
|
||||||
|
<div className="p-3 bg-light rounded h-100">
|
||||||
|
<h3>Einmalkauf (Pay-per-Game)</h3>
|
||||||
|
<p>Alternativ können Nutzer einzelne Spiele per Einmalkauf freischalten.</p>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-5">
|
||||||
|
<h2>10. Skalierbarkeit, Kosten & Fehlerbehandlung</h2>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Kostenkontrolle (OpenAI):</strong> Rate-Limiting auf dem Endpunkt zur Spielerstellung.</li>
|
||||||
|
<li><strong>Fehlerbehandlung bei Generierung:</strong> Backend unternimmt automatische Wiederholungsversuche.</li>
|
||||||
|
<li><strong>Nahtloses Wiederverbinden:</strong> Spieler können jederzeit wieder in ein laufendes Spiel einsteigen.</li>
|
||||||
|
<li><strong>Notfall-Dashboard (Host):</strong> Spoiler-freies Admin-Panel für den Host zur Spielsteuerung.</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-5">
|
||||||
|
<h2>11. Rechtliches & Datenschutz</h2>
|
||||||
|
<ul>
|
||||||
|
<li><strong>DSGVO-konforme Datenschutzerklärung</strong></li>
|
||||||
|
<li><strong>Impressum</strong></li>
|
||||||
|
<li><strong>Möglichkeit zur Löschung des Accounts</strong></li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</Container>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default KrimiDinner;
|
||||||
Loading…
Reference in New Issue
Block a user