Compare commits
35
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df33002d30 | ||
|
|
efed783e25 | ||
|
|
54f115204f | ||
|
|
ca45f38262 | ||
|
|
ffe0c7d689 | ||
|
|
0f8c45963c | ||
|
|
e60a6b7089 | ||
|
|
3eae906b34 | ||
|
|
ea7852256f | ||
|
|
ba3de2b63b | ||
|
|
c91bf1de24 | ||
|
|
c9687af788 | ||
|
|
1be6605f8a | ||
|
|
b26ec4191a | ||
|
|
51c6867c5b | ||
|
|
e4228a01a6 | ||
|
|
4284784bf3 | ||
|
|
26225725b3 | ||
|
|
1178359927 | ||
|
|
5f2eaf326a | ||
|
|
d8bc26a75b | ||
|
|
01ba580d34 | ||
|
|
cfa5985f44 | ||
|
|
a6abe939e8 | ||
|
|
ad18d79c18 | ||
|
|
ac15ba2130 | ||
|
|
e9888acf7e | ||
|
|
6a85879f66 | ||
|
|
b84985a970 | ||
|
|
aa4b725813 | ||
|
|
a9283e32a2 | ||
|
|
310ea81d42 | ||
|
|
c4c41c00ef | ||
|
|
8afe00ebe7 | ||
|
|
c9c80f3c52 |
+3
-1
@@ -1,2 +1,4 @@
|
|||||||
66_plasmaTr
|
66_plasmaTr
|
||||||
export/
|
91_sonnensystem
|
||||||
|
00_aMeta/toolz/CYOA/export
|
||||||
|
00_aMeta/toolz/CYOA/cyoa-engine
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
= Meta: System der aufsteigenden Dateien =
|
||||||
|
:toc:
|
||||||
|
:icons: font
|
||||||
|
|
||||||
|
== Das ist mein Reich, hier bin ich Gott
|
||||||
|
|
||||||
|
Nur wenige werden diesen Teil zu lesen bekommen also seit geehrt.
|
||||||
|
Werde beginnen die Branches zu pflegen und die Stuktur aufbauen.
|
||||||
|
|
||||||
|
[cols="4*", options="header"]
|
||||||
|
.Sichtbarkeit der Texte
|
||||||
|
|===
|
||||||
|
|**`sonnensystem`** |`feature/*`, `dev` |Du (Autor) |Neovim-Configs, `build.sh`, Rohnotizen, Canvas-Prototypen, Scratchpads.
|
||||||
|
|**`galaxie`**
|
||||||
|
|`alpha`, `testing`
|
||||||
|
|Gast-Schreiber, Beta-Leser
|
||||||
|
|Lore-Bibel, Styleguides, No-Go-Wortlisten, Validation-Hooks.
|
||||||
|
|**`galaxienhaufen`**
|
||||||
|
|`staging`, `release`
|
||||||
|
|Lektorat, Setzer
|
||||||
|
|Typografie-Themes, EPUB/PDF-Generatoren, Kapitel-Includes, Layout-Assets.
|
||||||
|
|**`universum`**
|
||||||
|
|`main` / `v1.0`
|
||||||
|
|Öffentlichkeit, Leser
|
||||||
|
|Kanonischer Text, Open-Source-Lizenz, Enzyklopädie/Glossar.
|
||||||
|
|===
|
||||||
|
|
||||||
|
=== to be done
|
||||||
|
|
||||||
|
* [] Diese Datei zu jedem Branch hierher ziehen
|
||||||
|
* [] Reposetory zu internen Gitlab Server Spiegel
|
||||||
|
* [] Auto Build Testen
|
||||||
|
* [] Galaxie Build Druckfahne
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
= Meta: System der aufsteigenden Dateien =
|
||||||
|
:toc:
|
||||||
|
:icons: font
|
||||||
|
|
||||||
|
== Willkomen auserwählter Leser/Schreiber
|
||||||
|
|
||||||
|
Hier sollten die Dinge eigendlich schon reibungslos funktionieren.
|
||||||
|
Aber soweit unten kann es schon mal vorkommen das etwas in stocken gerät, lass dich davon nicht entmutigen.
|
||||||
|
Frage den der dir diese Dokumente gegeben hat nach hilfe oder wo weitere zu finden ist.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[cols="4*", options="header"]
|
||||||
|
.Sichtbarkeit der Texte
|
||||||
|
|===
|
||||||
|
|**`galaxie`**
|
||||||
|
|`alpha`, `testing`
|
||||||
|
|Gast-Schreiber, Beta-Leser
|
||||||
|
|Lore-Bibel, Styleguides, No-Go-Wortlisten, Validation-Hooks.
|
||||||
|
|**`galaxienhaufen`**
|
||||||
|
|`staging`, `release`
|
||||||
|
|Lektorat, Setzer
|
||||||
|
|Typografie-Themes, EPUB/PDF-Generatoren, Kapitel-Includes, Layout-Assets.
|
||||||
|
|**`universum`**
|
||||||
|
|`main` / `v1.0`
|
||||||
|
|Öffentlichkeit, Leser
|
||||||
|
|Kanonischer Text, Open-Source-Lizenz, Enzyklopädie/Glossar.
|
||||||
|
|===
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
= Meta: System der aufsteigenden Dateien =
|
||||||
|
:toc:
|
||||||
|
:icons: font
|
||||||
|
|
||||||
|
== Willkomen lieber Leser
|
||||||
|
|
||||||
|
die letzte Stufe vor der Öffentlichkeit, tools und Dateien werden sich dann
|
||||||
|
dort finden wo sie erwartet werden. Druckstufe noch nicht ganz klar,
|
||||||
|
warte auf den ersten Text der gesetzt werden kann.
|
||||||
|
|
||||||
|
|
||||||
|
[cols="4*", options="header"]
|
||||||
|
.Sichtbarkeit der Texte
|
||||||
|
|**`galaxienhaufen`**
|
||||||
|
|`staging`, `release`
|
||||||
|
|Lektorat, Setzer
|
||||||
|
|Typografie-Themes, EPUB/PDF-Generatoren, Kapitel-Includes, Layout-Assets.
|
||||||
|
|**`universum`**
|
||||||
|
|`main` / `v1.0`
|
||||||
|
|Öffentlichkeit, Leser
|
||||||
|
|Kanonischer Text, Open-Source-Lizenz, Enzyklopädie/Glossar.
|
||||||
|
|===
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
= Meta: System der aufsteigenden Dateien =
|
||||||
|
:toc:
|
||||||
|
:icons: font
|
||||||
|
|
||||||
|
== Hallo Welt
|
||||||
|
|
||||||
|
Der Text hat das Ende seiner Reise reicht, ab hier kann jeder ihn lesen.
|
||||||
|
Für fast jeden sollte etwas zum Konsomieren dabei sein.
|
||||||
|
|
||||||
|
[cols="4*", options="header"]
|
||||||
|
.Sichtbarkeit der Texte
|
||||||
|
|**`universum`**
|
||||||
|
|`main` / `v1.0`
|
||||||
|
|Öffentlichkeit, Leser
|
||||||
|
|Kanonischer Text, Open-Source-Lizenz, Enzyklopädie/Glossar.
|
||||||
|
|===
|
||||||
|
|
||||||
|
=== Liste der Formate
|
||||||
|
|
||||||
|
* webseite
|
||||||
|
* ePub
|
||||||
|
* PDF
|
||||||
@@ -0,0 +1,641 @@
|
|||||||
|
= Design-System: Maschinen-Instanzen
|
||||||
|
:toc:
|
||||||
|
:toclevels: 3
|
||||||
|
|
||||||
|
Project X Tribut • Universelles UI-, HUD- und Grafiksystem
|
||||||
|
|
||||||
|
*Version:* 1.0.0 +
|
||||||
|
*Zielplattformen:* Web, HTML5 Canvas, Browser-Games, Diagnose-Terminals, Tools, Dashboards +
|
||||||
|
*Designsprache:* Hard-Sci-Fi • Industrial Computing • Retro-Terminal • Maschinenästhetik
|
||||||
|
|
||||||
|
== 1. Designphilosophie
|
||||||
|
|
||||||
|
Das Design-System *Maschinen-Instanzen* definiert die visuelle Sprache des gesamten Computer-Historyz-Universums.
|
||||||
|
|
||||||
|
Die Gestaltung orientiert sich an industriellen Steuerungssystemen, wissenschaftlichen Diagnoseterminals und kybernetischen Maschinenkomplexen. Sämtliche Farben, Formen und Effekte besitzen eine funktionale Bedeutung.
|
||||||
|
|
||||||
|
Die Benutzeroberfläche soll nicht dekorativ wirken, sondern wie ein Bestandteil einer realen Maschine.
|
||||||
|
|
||||||
|
=== Grundprinzipien
|
||||||
|
|
||||||
|
. Funktion vor Dekoration.
|
||||||
|
. Jede Farbe besitzt eine semantische Bedeutung.
|
||||||
|
. Scharfe Kanten statt organischer Formen.
|
||||||
|
. Monospace-Typografie als Standard.
|
||||||
|
. Technische Lesbarkeit hat Vorrang vor visuellen Effekten.
|
||||||
|
. Informationen werden durch Farbe, Position und Kontrast vermittelt.
|
||||||
|
. Animationen dienen der Zustandskommunikation und niemals ausschließlich der Verzierung.
|
||||||
|
|
||||||
|
== 2. Farbpalette
|
||||||
|
|
||||||
|
=== 2.1 Kernfarben
|
||||||
|
|
||||||
|
[cols="1,1,3",options="header"]
|
||||||
|
|===
|
||||||
|
|Name
|
||||||
|
|Hex
|
||||||
|
|Bedeutung
|
||||||
|
|
||||||
|
|Deep Void
|
||||||
|
|`#05070a`
|
||||||
|
|Globaler Hintergrund, tiefste Darstellungsebene
|
||||||
|
|
||||||
|
|Terminal Base
|
||||||
|
|`#0b0e14`
|
||||||
|
|Fenster, Container und Panel-Flächen
|
||||||
|
|
||||||
|
|Tech Cyan
|
||||||
|
|`#00f2ff`
|
||||||
|
|Interaktion, Fokus, aktive Systeme
|
||||||
|
|
||||||
|
|Harvest Green
|
||||||
|
|`#00ff73`
|
||||||
|
|Erfolg, Ressourcengewinn, Wiederherstellung
|
||||||
|
|
||||||
|
|Amber Gold
|
||||||
|
|`#ffb700`
|
||||||
|
|Warnungen, besondere Objekte, Missionsziele
|
||||||
|
|
||||||
|
|Critical Red
|
||||||
|
|`#ff3e3e`
|
||||||
|
|Kritische Zustände, Fehler, Gefahr
|
||||||
|
|
||||||
|
|Steel Grey
|
||||||
|
|`#888899`
|
||||||
|
|Sekundäre Informationen, deaktivierte Elemente
|
||||||
|
|===
|
||||||
|
|
||||||
|
=== 2.2 Semantische Zustände
|
||||||
|
|
||||||
|
[cols="1,1",options="header"]
|
||||||
|
|===
|
||||||
|
|Zustand
|
||||||
|
|Farbe
|
||||||
|
|
||||||
|
|Information
|
||||||
|
|Tech Cyan
|
||||||
|
|
||||||
|
|Erfolg
|
||||||
|
|Harvest Green
|
||||||
|
|
||||||
|
|Warnung
|
||||||
|
|Amber Gold
|
||||||
|
|
||||||
|
|Kritisch
|
||||||
|
|Critical Red
|
||||||
|
|
||||||
|
|Deaktiviert
|
||||||
|
|Steel Grey
|
||||||
|
|
||||||
|
|Fokus
|
||||||
|
|Tech Cyan + Glow
|
||||||
|
|===
|
||||||
|
|
||||||
|
=== 2.3 Priorisierung
|
||||||
|
|
||||||
|
==== Primär
|
||||||
|
|
||||||
|
Interaktive Objekte:
|
||||||
|
|
||||||
|
* Buttons
|
||||||
|
* Links
|
||||||
|
* Menüs
|
||||||
|
* Aktive Systeme
|
||||||
|
|
||||||
|
Verwenden:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
Tech Cyan
|
||||||
|
----
|
||||||
|
|
||||||
|
==== Sekundär
|
||||||
|
|
||||||
|
Nicht-interaktive Daten:
|
||||||
|
|
||||||
|
* Metadaten
|
||||||
|
* Diagnostikwerte
|
||||||
|
* Statistiken
|
||||||
|
|
||||||
|
Verwenden:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
Steel Grey
|
||||||
|
----
|
||||||
|
|
||||||
|
==== Kritisch
|
||||||
|
|
||||||
|
Fehler oder Gefahr:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
Critical Red
|
||||||
|
----
|
||||||
|
|
||||||
|
== 3. Typografie
|
||||||
|
|
||||||
|
=== 3.1 Schriftarten
|
||||||
|
|
||||||
|
Ausschließlich Monospace-Schriften.
|
||||||
|
|
||||||
|
Bevorzugte Reihenfolge:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
JetBrains Mono
|
||||||
|
Fira Code
|
||||||
|
Courier Prime
|
||||||
|
monospace
|
||||||
|
----
|
||||||
|
|
||||||
|
=== 3.2 Typografische Regeln
|
||||||
|
|
||||||
|
==== Beschriftungen
|
||||||
|
|
||||||
|
Verwendung von Kleinbuchstaben.
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
shield status
|
||||||
|
resource storage
|
||||||
|
diagnostics
|
||||||
|
----
|
||||||
|
|
||||||
|
==== Statusmeldungen
|
||||||
|
|
||||||
|
Fett darstellen.
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
WARNING
|
||||||
|
SHIELD FAILURE
|
||||||
|
RECOVERY COMPLETE
|
||||||
|
----
|
||||||
|
|
||||||
|
=== 3.3 Lesbarkeit
|
||||||
|
|
||||||
|
Grundregeln:
|
||||||
|
|
||||||
|
[source,css]
|
||||||
|
----
|
||||||
|
line-height: 1.4;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
----
|
||||||
|
|
||||||
|
Text muss stets lesbar bleiben.
|
||||||
|
|
||||||
|
Dekorative Effekte dürfen niemals die Lesbarkeit reduzieren.
|
||||||
|
|
||||||
|
=== 3.4 Text-Glow
|
||||||
|
|
||||||
|
Optional:
|
||||||
|
|
||||||
|
[source,css]
|
||||||
|
----
|
||||||
|
text-shadow:
|
||||||
|
0 0 3px rgba(0,242,255,0.3);
|
||||||
|
----
|
||||||
|
|
||||||
|
Maximal:
|
||||||
|
|
||||||
|
* 3px Blur
|
||||||
|
* 30 % Deckkraft
|
||||||
|
|
||||||
|
== 4. Layout-System
|
||||||
|
|
||||||
|
=== 4.1 Raster
|
||||||
|
|
||||||
|
Empfohlenes Grundraster:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
8px System
|
||||||
|
----
|
||||||
|
|
||||||
|
Abstände erfolgen in Vielfachen von:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
8
|
||||||
|
16
|
||||||
|
24
|
||||||
|
32
|
||||||
|
48
|
||||||
|
64
|
||||||
|
----
|
||||||
|
|
||||||
|
=== 4.2 Informationshierarchie
|
||||||
|
|
||||||
|
Von links nach rechts:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
Systemstatus
|
||||||
|
↓
|
||||||
|
Navigation
|
||||||
|
↓
|
||||||
|
Primäre Inhalte
|
||||||
|
↓
|
||||||
|
Kontextinformationen
|
||||||
|
----
|
||||||
|
|
||||||
|
=== 4.3 Bildaufteilung
|
||||||
|
|
||||||
|
Für Spiele:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
Links:
|
||||||
|
Systeme / HUD
|
||||||
|
|
||||||
|
Mitte:
|
||||||
|
Gameplay
|
||||||
|
|
||||||
|
Rechts:
|
||||||
|
Freier Sichtbereich
|
||||||
|
----
|
||||||
|
|
||||||
|
== 5. HUD-Spezifikation
|
||||||
|
|
||||||
|
=== 5.1 Grundkonzept
|
||||||
|
|
||||||
|
HUD-Elemente wirken wie physische Bestandteile der Maschine.
|
||||||
|
|
||||||
|
Keine schwebenden Fantasy-Elemente.
|
||||||
|
|
||||||
|
Keine organischen Formen.
|
||||||
|
|
||||||
|
=== 5.2 Statusanzeigen
|
||||||
|
|
||||||
|
==== Schild
|
||||||
|
|
||||||
|
Farbübergang:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
>60%
|
||||||
|
Tech Cyan
|
||||||
|
|
||||||
|
30%-60%
|
||||||
|
Amber Gold
|
||||||
|
|
||||||
|
<30%
|
||||||
|
Critical Red
|
||||||
|
----
|
||||||
|
|
||||||
|
==== Ressourcen
|
||||||
|
|
||||||
|
Verwendung:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
Harvest Green
|
||||||
|
----
|
||||||
|
|
||||||
|
==== Systemfehler
|
||||||
|
|
||||||
|
Verwendung:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
Critical Red
|
||||||
|
----
|
||||||
|
|
||||||
|
== 6. Canvas-Effekte
|
||||||
|
|
||||||
|
=== 6.1 Scan-Lines
|
||||||
|
|
||||||
|
Zweck:
|
||||||
|
|
||||||
|
Simulation eines industriellen Monitors.
|
||||||
|
|
||||||
|
Empfohlene Farbe:
|
||||||
|
|
||||||
|
[source,css]
|
||||||
|
----
|
||||||
|
rgba(255,255,255,0.03)
|
||||||
|
----
|
||||||
|
|
||||||
|
Regeln:
|
||||||
|
|
||||||
|
* Über der Spielwelt
|
||||||
|
* Unter der UI
|
||||||
|
* Dürfen Lesbarkeit nicht beeinträchtigen
|
||||||
|
|
||||||
|
=== 6.2 Glitch-Effekte
|
||||||
|
|
||||||
|
Technische Störungen werden durch kurze Cyan-Artefakte dargestellt.
|
||||||
|
|
||||||
|
Regeln:
|
||||||
|
|
||||||
|
* Maximal 150 ms sichtbar
|
||||||
|
* Nur ereignisgesteuert
|
||||||
|
* Keine permanente Darstellung
|
||||||
|
|
||||||
|
Mögliche Auslöser:
|
||||||
|
|
||||||
|
* Schildausfall
|
||||||
|
* Respawn
|
||||||
|
* Energieumschaltung
|
||||||
|
* Speichertransfer
|
||||||
|
* Diagnostikfehler
|
||||||
|
|
||||||
|
=== 6.3 Bildschirmrauschen
|
||||||
|
|
||||||
|
Optional:
|
||||||
|
|
||||||
|
[source,css]
|
||||||
|
----
|
||||||
|
opacity: 0.02 - 0.04
|
||||||
|
----
|
||||||
|
|
||||||
|
Niemals dominant.
|
||||||
|
|
||||||
|
== 7. Rahmen-System
|
||||||
|
|
||||||
|
=== 7.1 Grundregel
|
||||||
|
|
||||||
|
Vermeide klassische Betriebssystem-Fenster.
|
||||||
|
|
||||||
|
Stattdessen:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
┌─────────
|
||||||
|
|
||||||
|
└─────────
|
||||||
|
----
|
||||||
|
|
||||||
|
oder Corner-Brackets.
|
||||||
|
|
||||||
|
=== 7.2 Rundungen
|
||||||
|
|
||||||
|
Nicht vorgesehen.
|
||||||
|
|
||||||
|
Maximal:
|
||||||
|
|
||||||
|
[source,css]
|
||||||
|
----
|
||||||
|
border-radius: 2px;
|
||||||
|
----
|
||||||
|
|
||||||
|
=== 7.3 Linien
|
||||||
|
|
||||||
|
Immer:
|
||||||
|
|
||||||
|
[source,css]
|
||||||
|
----
|
||||||
|
1px
|
||||||
|
----
|
||||||
|
|
||||||
|
Farbe:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
Steel Grey
|
||||||
|
----
|
||||||
|
|
||||||
|
Aktiv:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
Tech Cyan
|
||||||
|
----
|
||||||
|
|
||||||
|
== 8. Buttons
|
||||||
|
|
||||||
|
=== Normal
|
||||||
|
|
||||||
|
[source,css]
|
||||||
|
----
|
||||||
|
background: transparent;
|
||||||
|
color: #888899;
|
||||||
|
border: 1px solid #888899;
|
||||||
|
----
|
||||||
|
|
||||||
|
=== Hover
|
||||||
|
|
||||||
|
[source,css]
|
||||||
|
----
|
||||||
|
color: #00f2ff;
|
||||||
|
border-color: #00f2ff;
|
||||||
|
|
||||||
|
box-shadow:
|
||||||
|
0 0 8px #00f2ff;
|
||||||
|
----
|
||||||
|
|
||||||
|
=== Aktiv
|
||||||
|
|
||||||
|
[source,css]
|
||||||
|
----
|
||||||
|
background: #00f2ff;
|
||||||
|
color: #05070a;
|
||||||
|
----
|
||||||
|
|
||||||
|
=== Disabled
|
||||||
|
|
||||||
|
[source,css]
|
||||||
|
----
|
||||||
|
opacity: 0.4;
|
||||||
|
pointer-events: none;
|
||||||
|
----
|
||||||
|
|
||||||
|
== 9. Panels und Container
|
||||||
|
|
||||||
|
=== Standard
|
||||||
|
|
||||||
|
[source,css]
|
||||||
|
----
|
||||||
|
background: #0b0e14;
|
||||||
|
border: 1px solid #888899;
|
||||||
|
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
----
|
||||||
|
|
||||||
|
=== Overlays
|
||||||
|
|
||||||
|
Dürfen Schatten besitzen.
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
[source,css]
|
||||||
|
----
|
||||||
|
box-shadow:
|
||||||
|
8px 8px 0 rgba(0,0,0,0.8);
|
||||||
|
----
|
||||||
|
|
||||||
|
=== Schatten-Regel
|
||||||
|
|
||||||
|
Verboten:
|
||||||
|
|
||||||
|
* Weiche Material-Schatten
|
||||||
|
* Neumorphe Effekte
|
||||||
|
* Mobile-App-Schatten
|
||||||
|
|
||||||
|
Erlaubt:
|
||||||
|
|
||||||
|
* Harte technische Schatten
|
||||||
|
|
||||||
|
== 10. Icon-System
|
||||||
|
|
||||||
|
=== Stil
|
||||||
|
|
||||||
|
Alle Icons müssen:
|
||||||
|
|
||||||
|
* SVG-basiert sein
|
||||||
|
* Geometrisch wirken
|
||||||
|
* Scharfe Kanten besitzen
|
||||||
|
|
||||||
|
=== Unzulässig
|
||||||
|
|
||||||
|
* Airbrush
|
||||||
|
* Illustrationen
|
||||||
|
* Farbverläufe
|
||||||
|
* Cartoon-Stil
|
||||||
|
|
||||||
|
=== Zulässig
|
||||||
|
|
||||||
|
* Technische Symbole
|
||||||
|
* Schaltpläne
|
||||||
|
* Maschinen-Piktogramme
|
||||||
|
|
||||||
|
== 11. Asset-Pipeline
|
||||||
|
|
||||||
|
=== Flächen
|
||||||
|
|
||||||
|
Nur Vollfarben.
|
||||||
|
|
||||||
|
=== Nicht erlaubt
|
||||||
|
|
||||||
|
* Farbverläufe
|
||||||
|
* Weiche Lichtflächen
|
||||||
|
* Fototexturen im UI
|
||||||
|
|
||||||
|
=== Ausnahmen
|
||||||
|
|
||||||
|
Folgende Effekte dürfen Verläufe enthalten:
|
||||||
|
|
||||||
|
* Glow
|
||||||
|
* Bloom
|
||||||
|
* Partikel
|
||||||
|
* Plasma
|
||||||
|
* Energieeffekte
|
||||||
|
|
||||||
|
== 12. Lichtsystem
|
||||||
|
|
||||||
|
=== Ziel
|
||||||
|
|
||||||
|
Licht soll technisch wirken.
|
||||||
|
|
||||||
|
Nicht magisch.
|
||||||
|
|
||||||
|
Nicht organisch.
|
||||||
|
|
||||||
|
Nicht dekorativ.
|
||||||
|
|
||||||
|
=== Glow-Regeln
|
||||||
|
|
||||||
|
Empfohlen:
|
||||||
|
|
||||||
|
[source,css]
|
||||||
|
----
|
||||||
|
box-shadow:
|
||||||
|
0 0 6px currentColor;
|
||||||
|
----
|
||||||
|
|
||||||
|
Eigenschaften:
|
||||||
|
|
||||||
|
* Kurzer Radius
|
||||||
|
* Hoher Kontrast
|
||||||
|
* Klar abgegrenzte Lichtquellen
|
||||||
|
|
||||||
|
== 13. Animationen
|
||||||
|
|
||||||
|
=== Erlaubt
|
||||||
|
|
||||||
|
* Blinken
|
||||||
|
* Pulsieren
|
||||||
|
* Statuswechsel
|
||||||
|
* Diagnostik-Animationen
|
||||||
|
* Ladeanzeigen
|
||||||
|
|
||||||
|
=== Nicht erlaubt
|
||||||
|
|
||||||
|
* Verspielte Übergänge
|
||||||
|
* Elastische Animationen
|
||||||
|
* Übertriebene Bewegungen
|
||||||
|
|
||||||
|
=== Animationsdauer
|
||||||
|
|
||||||
|
Empfohlen:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
100ms - 300ms
|
||||||
|
----
|
||||||
|
|
||||||
|
HUD-Reaktionen:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
50ms - 150ms
|
||||||
|
----
|
||||||
|
|
||||||
|
== 14. Referenz-CSS
|
||||||
|
|
||||||
|
[source,css]
|
||||||
|
----
|
||||||
|
:root {
|
||||||
|
--bg-deep: #05070a;
|
||||||
|
--bg-panel: #0b0e14;
|
||||||
|
|
||||||
|
--accent-cyan: #00f2ff;
|
||||||
|
--accent-green: #00ff73;
|
||||||
|
--accent-amber: #ffb700;
|
||||||
|
--accent-red: #ff3e3e;
|
||||||
|
|
||||||
|
--text-dim: #888899;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: var(--bg-deep);
|
||||||
|
color: var(--text-dim);
|
||||||
|
|
||||||
|
font-family:
|
||||||
|
"JetBrains Mono",
|
||||||
|
"Fira Code",
|
||||||
|
"Courier Prime",
|
||||||
|
monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
background: var(--bg-panel);
|
||||||
|
border: 1px solid var(--text-dim);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
color: var(--accent-cyan);
|
||||||
|
border-color: var(--accent-cyan);
|
||||||
|
|
||||||
|
box-shadow:
|
||||||
|
0 0 8px var(--accent-cyan);
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
== Design-Leitsatz
|
||||||
|
|
||||||
|
*Maschinen-Instanzen ist kein futuristisches Betriebssystem.*
|
||||||
|
|
||||||
|
Es ist die Benutzeroberfläche einer gewaltigen industriellen Maschine, die zufällig von Menschen bedient wird.
|
||||||
|
|
||||||
|
Jedes Element soll vermitteln, dass unter der Oberfläche reale Energieflüsse, Diagnosesysteme, Speicherabbilder, Förderanlagen und Maschinenprozesse arbeiten.
|
||||||
|
|
||||||
|
Dekoration ist optional.
|
||||||
|
|
||||||
|
*Funktion ist Pflicht.*
|
||||||
@@ -0,0 +1,648 @@
|
|||||||
|
# Design-System: Maschinen-Instanzen
|
||||||
|
### Project X Tribut • Universelles UI-, HUD- und Grafiksystem
|
||||||
|
|
||||||
|
**Version:** 1.0.0
|
||||||
|
**Zielplattformen:** Web, HTML5 Canvas, Browser-Games, Diagnose-Terminals, Tools, Dashboards
|
||||||
|
**Designsprache:** Hard-Sci-Fi · Industrial Computing · Retro-Terminal · Maschinenästhetik
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 1. Designphilosophie
|
||||||
|
|
||||||
|
Das Design-System *Maschinen-Instanzen* definiert die visuelle Sprache des gesamten Computer-Historyz-Universums.
|
||||||
|
|
||||||
|
Die Gestaltung orientiert sich an industriellen Steuerungssystemen, wissenschaftlichen Diagnoseterminals und kybernetischen Maschinenkomplexen. Sämtliche Farben, Formen und Effekte besitzen eine funktionale Bedeutung.
|
||||||
|
|
||||||
|
Die Benutzeroberfläche soll nicht dekorativ wirken, sondern wie ein Bestandteil einer realen Maschine.
|
||||||
|
|
||||||
|
## Grundprinzipien
|
||||||
|
|
||||||
|
1. Funktion vor Dekoration.
|
||||||
|
2. Jede Farbe besitzt eine semantische Bedeutung.
|
||||||
|
3. Scharfe Kanten statt organischer Formen.
|
||||||
|
4. Monospace-Typografie als Standard.
|
||||||
|
5. Technische Lesbarkeit hat Vorrang vor visuellen Effekten.
|
||||||
|
6. Informationen werden durch Farbe, Position und Kontrast vermittelt.
|
||||||
|
7. Animationen dienen der Zustandskommunikation und niemals ausschließlich der Verzierung.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 2. Farbpalette
|
||||||
|
|
||||||
|
## 2.1 Kernfarben
|
||||||
|
|
||||||
|
| Name | Hex | Bedeutung |
|
||||||
|
|--------|--------|--------|
|
||||||
|
| Deep Void | `#05070a` | Globaler Hintergrund, tiefste Darstellungsebene |
|
||||||
|
| Terminal Base | `#0b0e14` | Fenster, Container und Panel-Flächen |
|
||||||
|
| Tech Cyan | `#00f2ff` | Interaktion, Fokus, aktive Systeme |
|
||||||
|
| Harvest Green | `#00ff73` | Erfolg, Ressourcengewinn, Wiederherstellung |
|
||||||
|
| Amber Gold | `#ffb700` | Warnungen, besondere Objekte, Missionsziele |
|
||||||
|
| Critical Red | `#ff3e3e` | Kritische Zustände, Fehler, Gefahr |
|
||||||
|
| Steel Grey | `#888899` | Sekundäre Informationen, deaktivierte Elemente |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2.2 Semantische Zustände
|
||||||
|
|
||||||
|
| Zustand | Farbe |
|
||||||
|
|----------|----------|
|
||||||
|
| Information | Tech Cyan |
|
||||||
|
| Erfolg | Harvest Green |
|
||||||
|
| Warnung | Amber Gold |
|
||||||
|
| Kritisch | Critical Red |
|
||||||
|
| Deaktiviert | Steel Grey |
|
||||||
|
| Fokus | Tech Cyan + Glow |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2.3 Priorisierung
|
||||||
|
|
||||||
|
### Primär
|
||||||
|
|
||||||
|
Interaktive Objekte:
|
||||||
|
|
||||||
|
- Buttons
|
||||||
|
- Links
|
||||||
|
- Menüs
|
||||||
|
- Aktive Systeme
|
||||||
|
|
||||||
|
Verwenden:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Tech Cyan
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sekundär
|
||||||
|
|
||||||
|
Nicht-interaktive Daten:
|
||||||
|
|
||||||
|
- Metadaten
|
||||||
|
- Diagnostikwerte
|
||||||
|
- Statistiken
|
||||||
|
|
||||||
|
Verwenden:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Steel Grey
|
||||||
|
```
|
||||||
|
|
||||||
|
### Kritisch
|
||||||
|
|
||||||
|
Fehler oder Gefahr:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Critical Red
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 3. Typografie
|
||||||
|
|
||||||
|
## 3.1 Schriftarten
|
||||||
|
|
||||||
|
Ausschließlich Monospace-Schriften.
|
||||||
|
|
||||||
|
Bevorzugte Reihenfolge:
|
||||||
|
|
||||||
|
```text
|
||||||
|
JetBrains Mono
|
||||||
|
Fira Code
|
||||||
|
Courier Prime
|
||||||
|
monospace
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3.2 Typografische Regeln
|
||||||
|
|
||||||
|
### Beschriftungen
|
||||||
|
|
||||||
|
Verwendung von Kleinbuchstaben.
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
```text
|
||||||
|
shield status
|
||||||
|
resource storage
|
||||||
|
diagnostics
|
||||||
|
```
|
||||||
|
|
||||||
|
### Statusmeldungen
|
||||||
|
|
||||||
|
Fett darstellen.
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
```text
|
||||||
|
WARNING
|
||||||
|
SHIELD FAILURE
|
||||||
|
RECOVERY COMPLETE
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3.3 Lesbarkeit
|
||||||
|
|
||||||
|
Grundregeln:
|
||||||
|
|
||||||
|
```css
|
||||||
|
line-height: 1.4;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
```
|
||||||
|
|
||||||
|
Text muss stets lesbar bleiben.
|
||||||
|
|
||||||
|
Dekorative Effekte dürfen niemals die Lesbarkeit reduzieren.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3.4 Text-Glow
|
||||||
|
|
||||||
|
Optional:
|
||||||
|
|
||||||
|
```css
|
||||||
|
text-shadow:
|
||||||
|
0 0 3px rgba(0,242,255,0.3);
|
||||||
|
```
|
||||||
|
|
||||||
|
Maximal:
|
||||||
|
|
||||||
|
- 3px Blur
|
||||||
|
- 30% Deckkraft
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 4. Layout-System
|
||||||
|
|
||||||
|
## 4.1 Raster
|
||||||
|
|
||||||
|
Empfohlenes Grundraster:
|
||||||
|
|
||||||
|
```text
|
||||||
|
8px System
|
||||||
|
```
|
||||||
|
|
||||||
|
Abstände erfolgen in Vielfachen von:
|
||||||
|
|
||||||
|
```text
|
||||||
|
8
|
||||||
|
16
|
||||||
|
24
|
||||||
|
32
|
||||||
|
48
|
||||||
|
64
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4.2 Informationshierarchie
|
||||||
|
|
||||||
|
Von links nach rechts:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Systemstatus
|
||||||
|
↓
|
||||||
|
Navigation
|
||||||
|
↓
|
||||||
|
Primäre Inhalte
|
||||||
|
↓
|
||||||
|
Kontextinformationen
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4.3 Bildaufteilung
|
||||||
|
|
||||||
|
Für Spiele:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Links:
|
||||||
|
Systeme / HUD
|
||||||
|
|
||||||
|
Mitte:
|
||||||
|
Gameplay
|
||||||
|
|
||||||
|
Rechts:
|
||||||
|
Freier Sichtbereich
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 5. HUD-Spezifikation
|
||||||
|
|
||||||
|
## 5.1 Grundkonzept
|
||||||
|
|
||||||
|
HUD-Elemente wirken wie physische Bestandteile der Maschine.
|
||||||
|
|
||||||
|
Keine schwebenden Fantasy-Elemente.
|
||||||
|
|
||||||
|
Keine organischen Formen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5.2 Statusanzeigen
|
||||||
|
|
||||||
|
### Schild
|
||||||
|
|
||||||
|
Farbübergang:
|
||||||
|
|
||||||
|
```text
|
||||||
|
>60%
|
||||||
|
Tech Cyan
|
||||||
|
|
||||||
|
30%-60%
|
||||||
|
Amber Gold
|
||||||
|
|
||||||
|
<30%
|
||||||
|
Critical Red
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Ressourcen
|
||||||
|
|
||||||
|
Verwendung:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Harvest Green
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Systemfehler
|
||||||
|
|
||||||
|
Verwendung:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Critical Red
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 6. Canvas-Effekte
|
||||||
|
|
||||||
|
## 6.1 Scan-Lines
|
||||||
|
|
||||||
|
Zweck:
|
||||||
|
|
||||||
|
Simulation eines industriellen Monitors.
|
||||||
|
|
||||||
|
Empfohlene Farbe:
|
||||||
|
|
||||||
|
```css
|
||||||
|
rgba(255,255,255,0.03)
|
||||||
|
```
|
||||||
|
|
||||||
|
Regeln:
|
||||||
|
|
||||||
|
- Über der Spielwelt
|
||||||
|
- Unter der UI
|
||||||
|
- Dürfen Lesbarkeit nicht beeinträchtigen
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.2 Glitch-Effekte
|
||||||
|
|
||||||
|
Technische Störungen werden durch kurze Cyan-Artefakte dargestellt.
|
||||||
|
|
||||||
|
Regeln:
|
||||||
|
|
||||||
|
- Maximal 150 ms sichtbar
|
||||||
|
- Nur ereignisgesteuert
|
||||||
|
- Keine permanente Darstellung
|
||||||
|
|
||||||
|
Mögliche Auslöser:
|
||||||
|
|
||||||
|
- Schildausfall
|
||||||
|
- Respawn
|
||||||
|
- Energieumschaltung
|
||||||
|
- Speichertransfer
|
||||||
|
- Diagnostikfehler
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.3 Bildschirmrauschen
|
||||||
|
|
||||||
|
Optional:
|
||||||
|
|
||||||
|
```css
|
||||||
|
opacity: 0.02 - 0.04
|
||||||
|
```
|
||||||
|
|
||||||
|
Niemals dominant.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 7. Rahmen-System
|
||||||
|
|
||||||
|
## 7.1 Grundregel
|
||||||
|
|
||||||
|
Vermeide klassische Betriebssystem-Fenster.
|
||||||
|
|
||||||
|
Stattdessen:
|
||||||
|
|
||||||
|
```text
|
||||||
|
┌─────────
|
||||||
|
|
||||||
|
└─────────
|
||||||
|
```
|
||||||
|
|
||||||
|
bzw. Corner-Brackets.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7.2 Rundungen
|
||||||
|
|
||||||
|
Nicht vorgesehen.
|
||||||
|
|
||||||
|
Maximal:
|
||||||
|
|
||||||
|
```css
|
||||||
|
border-radius: 2px;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7.3 Linien
|
||||||
|
|
||||||
|
Immer:
|
||||||
|
|
||||||
|
```css
|
||||||
|
1px
|
||||||
|
```
|
||||||
|
|
||||||
|
Farbe:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Steel Grey
|
||||||
|
```
|
||||||
|
|
||||||
|
Aktiv:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Tech Cyan
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 8. Buttons
|
||||||
|
|
||||||
|
## Normal
|
||||||
|
|
||||||
|
```css
|
||||||
|
background: transparent;
|
||||||
|
color: #888899;
|
||||||
|
border: 1px solid #888899;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Hover
|
||||||
|
|
||||||
|
```css
|
||||||
|
color: #00f2ff;
|
||||||
|
border-color: #00f2ff;
|
||||||
|
|
||||||
|
box-shadow:
|
||||||
|
0 0 8px #00f2ff;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Aktiv
|
||||||
|
|
||||||
|
```css
|
||||||
|
background: #00f2ff;
|
||||||
|
color: #05070a;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Disabled
|
||||||
|
|
||||||
|
```css
|
||||||
|
opacity: 0.4;
|
||||||
|
pointer-events: none;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 9. Panels und Container
|
||||||
|
|
||||||
|
## Standard
|
||||||
|
|
||||||
|
```css
|
||||||
|
background: #0b0e14;
|
||||||
|
border: 1px solid #888899;
|
||||||
|
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overlays
|
||||||
|
|
||||||
|
Dürfen Schatten besitzen.
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
```css
|
||||||
|
box-shadow:
|
||||||
|
8px 8px 0 rgba(0,0,0,0.8);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Schatten-Regel
|
||||||
|
|
||||||
|
Verboten:
|
||||||
|
|
||||||
|
- weiche Material-Schatten
|
||||||
|
- neumorphe Effekte
|
||||||
|
- mobile App Shadows
|
||||||
|
|
||||||
|
Erlaubt:
|
||||||
|
|
||||||
|
- harte technische Schatten
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 10. Icon-System
|
||||||
|
|
||||||
|
## Stil
|
||||||
|
|
||||||
|
Alle Icons müssen:
|
||||||
|
|
||||||
|
- SVG-basiert sein
|
||||||
|
- geometrisch wirken
|
||||||
|
- scharfe Kanten besitzen
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Unzulässig
|
||||||
|
|
||||||
|
- Airbrush
|
||||||
|
- Illustrationen
|
||||||
|
- Farbverläufe
|
||||||
|
- Cartoon-Stil
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Zulässig
|
||||||
|
|
||||||
|
- technische Symbole
|
||||||
|
- Schaltpläne
|
||||||
|
- Maschinen-Piktogramme
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 11. Asset-Pipeline
|
||||||
|
|
||||||
|
## Flächen
|
||||||
|
|
||||||
|
Nur Vollfarben.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Nicht erlaubt
|
||||||
|
|
||||||
|
- Farbverläufe
|
||||||
|
- weiche Lichtflächen
|
||||||
|
- Fototexturen im UI
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Ausnahmen
|
||||||
|
|
||||||
|
Folgende Effekte dürfen Verläufe enthalten:
|
||||||
|
|
||||||
|
- Glow
|
||||||
|
- Bloom
|
||||||
|
- Partikel
|
||||||
|
- Plasma
|
||||||
|
- Energieeffekte
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 12. Lichtsystem
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
|
||||||
|
Licht soll technisch wirken.
|
||||||
|
|
||||||
|
Nicht magisch.
|
||||||
|
|
||||||
|
Nicht organisch.
|
||||||
|
|
||||||
|
Nicht dekorativ.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Glow-Regeln
|
||||||
|
|
||||||
|
Empfohlen:
|
||||||
|
|
||||||
|
```css
|
||||||
|
box-shadow:
|
||||||
|
0 0 6px currentColor;
|
||||||
|
```
|
||||||
|
|
||||||
|
Eigenschaften:
|
||||||
|
|
||||||
|
- kurzer Radius
|
||||||
|
- hoher Kontrast
|
||||||
|
- klar abgegrenzte Lichtquellen
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 13. Animationen
|
||||||
|
|
||||||
|
## Erlaubt
|
||||||
|
|
||||||
|
- Blinken
|
||||||
|
- Pulsieren
|
||||||
|
- Statuswechsel
|
||||||
|
- Diagnostik-Animationen
|
||||||
|
- Ladeanzeigen
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Nicht erlaubt
|
||||||
|
|
||||||
|
- verspielte Übergänge
|
||||||
|
- elastische Animationen
|
||||||
|
- übertriebene Bewegungen
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Animationsdauer
|
||||||
|
|
||||||
|
Empfohlen:
|
||||||
|
|
||||||
|
```text
|
||||||
|
100ms - 300ms
|
||||||
|
```
|
||||||
|
|
||||||
|
HUD-Reaktionen:
|
||||||
|
|
||||||
|
```text
|
||||||
|
50ms - 150ms
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 14. Referenz-CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
:root {
|
||||||
|
--bg-deep: #05070a;
|
||||||
|
--bg-panel: #0b0e14;
|
||||||
|
|
||||||
|
--accent-cyan: #00f2ff;
|
||||||
|
--accent-green: #00ff73;
|
||||||
|
--accent-amber: #ffb700;
|
||||||
|
--accent-red: #ff3e3e;
|
||||||
|
|
||||||
|
--text-dim: #888899;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: var(--bg-deep);
|
||||||
|
color: var(--text-dim);
|
||||||
|
|
||||||
|
font-family:
|
||||||
|
"JetBrains Mono",
|
||||||
|
"Fira Code",
|
||||||
|
"Courier Prime",
|
||||||
|
monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
background: var(--bg-panel);
|
||||||
|
border: 1px solid var(--text-dim);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
color: var(--accent-cyan);
|
||||||
|
border-color: var(--accent-cyan);
|
||||||
|
|
||||||
|
box-shadow:
|
||||||
|
0 0 8px var(--accent-cyan);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Design-Leitsatz
|
||||||
|
|
||||||
|
**Maschinen-Instanzen ist kein futuristisches Betriebssystem.**
|
||||||
|
|
||||||
|
Es ist die Benutzeroberfläche einer gewaltigen industriellen Maschine, die zufällig von Menschen bedient wird.
|
||||||
|
|
||||||
|
Jedes Element soll vermitteln, dass unter der Oberfläche reale Energieflüsse, Diagnosesysteme, Speicherabbilder, Förderanlagen und Maschinenprozesse arbeiten.
|
||||||
|
|
||||||
|
Dekoration ist optional.
|
||||||
|
|
||||||
|
Funktion ist Pflicht.
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
= REVERSE GAME DESIGN DOCUMENT (GDD)
|
||||||
|
:toc: left
|
||||||
|
:toclevels: 3
|
||||||
|
|
||||||
|
Projekt: Maschinen-Instanzen – Asteroiden-Sektor (Project X Tribut)
|
||||||
|
|
||||||
|
*Version:* 1.0.0 +
|
||||||
|
*Genre:* Hard-Sci-Fi / Retro-Shmup (2.5D) +
|
||||||
|
*Setting:* Das „Computer Historyz“-Universum (Sektor: Oortsche Wolke 42)
|
||||||
|
|
||||||
|
== 1. Vision & Kernkonzept
|
||||||
|
|
||||||
|
Ein endloses, horizontales Shoot-'em-up in 2D, das innerhalb einer echten 3D-Umgebung gerendert wird.
|
||||||
|
|
||||||
|
Der Spieler steuert eine kybernetische Ernte-Instanz (Bergbau-Schiff), die am Rand eines gigantischen, planetengroßen Maschinen-Ansaugstutzens operiert.
|
||||||
|
|
||||||
|
Das Spiel kombiniert rasante Arcade-Asteroiden-Zerstörung mit taktischem Power-Routing (Energie-Management) unter harten Hard-Sci-Fi-Rahmenbedingungen.
|
||||||
|
|
||||||
|
== 2. Globale Farbpalette & Ästhetik
|
||||||
|
|
||||||
|
Diese Farbpalette definiert das visuelle Leitbild für alle zukünftigen Spiele in diesem Universum, unabhängig davon, ob sie als Pixel-Art-, Vektor- oder PBR-basierte 3D-Titel umgesetzt werden.
|
||||||
|
|
||||||
|
=== 2.1 UI-, HUD- und Terminal-Farben (Window-Maker-Stil)
|
||||||
|
|
||||||
|
Die Benutzeroberfläche basiert auf dem kalten, funktionalen Look klassischer Unix-Terminals, kombiniert mit modernen Glow-Effekten.
|
||||||
|
|
||||||
|
[cols="1,1,3",options="header"]
|
||||||
|
|===
|
||||||
|
|Farbe
|
||||||
|
|Hex-Code
|
||||||
|
|Semantischer Nutzen
|
||||||
|
|
||||||
|
|Deep Void
|
||||||
|
|`#05070a`
|
||||||
|
|Globaler Weltraum-Hintergrund, tiefste Schatten.
|
||||||
|
|
||||||
|
|Terminal Base
|
||||||
|
|`#0d1117`
|
||||||
|
|Hintergrund für Menüs, HUD-Panels und Dialogfenster.
|
||||||
|
|
||||||
|
|Panel Border
|
||||||
|
|`#444c56`
|
||||||
|
|Rahmen von UI-Fenstern, häufig kombiniert mit inneren Highlights für 3D-Bevel-Effekte.
|
||||||
|
|
||||||
|
|Tech Cyan
|
||||||
|
|`#58a6ff`
|
||||||
|
|Primäre Akzentfarbe. Standard-Text, normale Laser, Hologramme, aktiver Schild (HP > 60 %) und UI-Glow.
|
||||||
|
|
||||||
|
|Harvest Green
|
||||||
|
|`#39d353`
|
||||||
|
|Erfolgs-Feedback, gesammelte Ressourcen und Laser-Stufe 2.
|
||||||
|
|
||||||
|
|Amber Gold
|
||||||
|
|`#d29922`
|
||||||
|
|Warnungen, Highscores, wertvolle Materialien, Schild (HP < 60 %) und Laser-Stufe 3.
|
||||||
|
|
||||||
|
|Critical Red
|
||||||
|
|`#f85149`
|
||||||
|
|Lebensgefahr, kritischer Schild (HP < 30 %), Triebwerks-Exhaust und Laser-Stufe 4+.
|
||||||
|
|===
|
||||||
|
|
||||||
|
=== 2.2 Materialfarben (3D-Modelle und 2D-Sprites)
|
||||||
|
|
||||||
|
Für gerenderte 3D-Objekte und gezeichnete 2D-Sprites gelten folgende Materialdefinitionen:
|
||||||
|
|
||||||
|
[cols="1,1,2,2",options="header"]
|
||||||
|
|===
|
||||||
|
|Element
|
||||||
|
|Farbe
|
||||||
|
|3D-Eigenschaften (PBR)
|
||||||
|
|2D-Eigenschaften
|
||||||
|
|
||||||
|
|Maschinen-Hülle
|
||||||
|
|`#1f6feb` (Blau-Metallic)
|
||||||
|
|Roughness: 0.4, Metalness: 0.8
|
||||||
|
|Satte dunkle Blautöne mit hartem weißen Specular-Highlight.
|
||||||
|
|
||||||
|
|Triebwerke / Rohre
|
||||||
|
|`#21262d` (Dunkelgrau)
|
||||||
|
|Roughness: 0.9, Metalness: 1.0
|
||||||
|
|Nahezu schwarze Flächen mit hohem Kontrast.
|
||||||
|
|
||||||
|
|Eis-Asteroid
|
||||||
|
|`#d0e8ff` (Blass-Eisblau)
|
||||||
|
|Roughness: 0.9, Metalness: 0.1
|
||||||
|
|Helle Töne, geringe Schattenbildung, weiße Staubpartikel.
|
||||||
|
|
||||||
|
|Fels-Asteroid
|
||||||
|
|`#6b4a31` (Braun)
|
||||||
|
|Roughness: 1.0, Metalness: 0.1
|
||||||
|
|Matte, strukturierte und körnige Oberflächen.
|
||||||
|
|
||||||
|
|Eisen-Asteroid
|
||||||
|
|`#888899` (Grau/Silber)
|
||||||
|
|Roughness: 0.3, Metalness: 0.9
|
||||||
|
|Spiegelnde Oberflächen mit deutlich sichtbaren Glanzlichtern.
|
||||||
|
|===
|
||||||
|
|
||||||
|
== 3. Gameplay & Mechaniken
|
||||||
|
|
||||||
|
=== 3.1 Das Plasma-Blasen-Paradoxon (Movement)
|
||||||
|
|
||||||
|
. *Lore-Hintergrund:*
|
||||||
|
Das Schiff erzeugt ein Magnetfeld zum Sammeln von Weltraumstaub. Dadurch entsteht eine künstliche Atmosphäre im Vakuum.
|
||||||
|
|
||||||
|
. *Mechanik:*
|
||||||
|
Das Schiff wird aerodynamisch gesteuert. Es fliegt nicht auf festen Schienen, sondern neigt sich beim Steigen und Sinken entlang einer simulierten Roll-/Yaw-Bewegung.
|
||||||
|
|
||||||
|
. *Feedback:*
|
||||||
|
Die Plasma-Blase pulsiert visuell. Mit steigender Schildenergie wächst ihre Größe von 0.6× bis 1.5× der Schiffsausdehnung.
|
||||||
|
|
||||||
|
=== 3.2 Taktisches Power-Routing (Energie-Management)
|
||||||
|
|
||||||
|
Die zentrale Hard-Sci-Fi-Mechanik basiert auf zwei Ressourcen:
|
||||||
|
|
||||||
|
* *Schild (Defensive)*
|
||||||
|
* *Laser / Score (Offensive)*
|
||||||
|
|
||||||
|
Der Spieler kann Energie in Echtzeit zwischen beiden Systemen umverteilen.
|
||||||
|
|
||||||
|
. *Schild laden (Defensive):*
|
||||||
|
Der Spieler opfert Score beziehungsweise Laserstufen, um den Schild wiederherzustellen.
|
||||||
|
|
||||||
|
. *Laser pushen (Offensive):*
|
||||||
|
Energie wird dem Schild entzogen und in die Waffensysteme umgeleitet.
|
||||||
|
|
||||||
|
. *Visuelle Regel:*
|
||||||
|
Dieses Risiko-Belohnungs-System muss in jeder Umsetzung über die Farbskala von `Tech Cyan` bis `Critical Red` dargestellt werden.
|
||||||
|
|
||||||
|
=== 3.3 Asteroiden-Split-Physik & Materialklassen
|
||||||
|
|
||||||
|
Gegnerische Asteroiden teilen sich beim Zerstören in zwei kleinere und schnellere Fragmente.
|
||||||
|
|
||||||
|
. *Eis (Level 1-2):*
|
||||||
|
1× Basis-HP. Schnell, aber äußerst fragil.
|
||||||
|
|
||||||
|
. *Gestein (Level 2-4):*
|
||||||
|
2× Basis-HP. Standardgegner.
|
||||||
|
|
||||||
|
. *Eisen (Level 3-5):*
|
||||||
|
4× Basis-HP. Massive Brocken mit dreifachem Scorewert. Schwache Laser werden vollständig blockiert.
|
||||||
|
|
||||||
|
=== 3.4 Das Cylon-Recovery-System (Game Over / Respawn)
|
||||||
|
|
||||||
|
. *Mechanik:*
|
||||||
|
Es existiert kein endgültiger Tod. Beim Verlust der Hülle wird das Speicherabbild gesichert.
|
||||||
|
|
||||||
|
. *Ablauf:*
|
||||||
|
Das Spiel pausiert.
|
||||||
|
|
||||||
|
Ein Diagnostik-Terminal meldet:
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
DIAGNOSTICS
|
||||||
|
Hull Destroyed
|
||||||
|
----
|
||||||
|
|
||||||
|
Ein roter Fortschrittsbalken füllt sich, während das Bewusstsein in eine neue Instanz übertragen wird.
|
||||||
|
|
||||||
|
Der Spieler behält Laser-Level und Langzeitfortschritt, verliert jedoch Zeit sowie laufende Multiplikatoren.
|
||||||
|
|
||||||
|
== 4. Räumliche Komposition (Kamera & Level-Architektur)
|
||||||
|
|
||||||
|
=== 4.1 Der C-Rahmen (Die Maschine)
|
||||||
|
|
||||||
|
. *Konzept:*
|
||||||
|
Der Spieler operiert nicht im leeren Raum. Die linke Bildschirmseite wird von der gewaltigen Hauptmaschine eingenommen.
|
||||||
|
|
||||||
|
. *Layout:*
|
||||||
|
Das Mahlwerk erscheint als massive Struktur im oberen und unteren linken Bildbereich.
|
||||||
|
|
||||||
|
* 3D: Box-Geometry
|
||||||
|
* 2D: Parallax-Layer
|
||||||
|
|
||||||
|
. *Der Korridor:*
|
||||||
|
Die mittlere Zone der linken Bildschirmhälfte bleibt frei und garantiert Sicht auf das Spielgeschehen.
|
||||||
|
|
||||||
|
. *Reaktivität:*
|
||||||
|
Trümmerfragmente werden nach links in den Schlund der Maschine gesaugt.
|
||||||
|
|
||||||
|
Mit zunehmender Materialzufuhr:
|
||||||
|
|
||||||
|
* Rotieren die Häcksler schneller.
|
||||||
|
* Verstärkt sich der Plasma-Halo.
|
||||||
|
* Steigt die visuelle Aktivität der Anlage.
|
||||||
|
|
||||||
|
=== 4.2 UI-Platzierung (HUD)
|
||||||
|
|
||||||
|
Das HUD integriert sich in den physischen C-Rahmen der Maschine.
|
||||||
|
|
||||||
|
. *Oben links:*
|
||||||
|
Schiff-Diagnostik (Schild, Laser, Statuswerte).
|
||||||
|
|
||||||
|
. *Unten links:*
|
||||||
|
Ressourcenanzeige (Punkte, Highscore, Materialzähler).
|
||||||
|
|
||||||
|
. *Ziel:*
|
||||||
|
Die rechte und zentrale Bildhälfte bleiben vollständig für das eigentliche Spielgeschehen reserviert.
|
||||||
|
|
||||||
|
== 5. Technische Struktur (Code-Architektur)
|
||||||
|
|
||||||
|
Für Programmierer definiert die Konfiguration `GAME_CONFIG` die zentrale Wahrheitsquelle.
|
||||||
|
|
||||||
|
Magic Numbers im Quellcode sind nicht zulässig.
|
||||||
|
|
||||||
|
Jede Umsetzung des Spiels muss mindestens folgende Strukturobjekte enthalten:
|
||||||
|
|
||||||
|
. `world`
|
||||||
|
+
|
||||||
|
Konstanten für Scrollgeschwindigkeit, Zeitskalierung und globale Simulation.
|
||||||
|
|
||||||
|
. `player`
|
||||||
|
+
|
||||||
|
Geschwindigkeit, Kollisionsradius und Basiswerte des Spielerschiffs.
|
||||||
|
|
||||||
|
. `laser`
|
||||||
|
+
|
||||||
|
Feuerrate, Schaden und Upgrade-Grenzen (Level 1-5).
|
||||||
|
|
||||||
|
. `asteroidTypes`
|
||||||
|
+
|
||||||
|
Dictionary zur Zuordnung von:
|
||||||
|
|
||||||
|
* Eis
|
||||||
|
* Gestein
|
||||||
|
* Eisen
|
||||||
|
|
||||||
|
mit:
|
||||||
|
|
||||||
|
* HP-Multiplikatoren
|
||||||
|
* Asset-Pfaden
|
||||||
|
* Sprite-Dateien (`.png`)
|
||||||
|
* 3D-Modellen (`.glb`)
|
||||||
|
|
||||||
|
. `levelWaves`
|
||||||
|
+
|
||||||
|
Wahrscheinlichkeitsmatrix zur Definition der Spawn-Verteilung von Asteroidentypen innerhalb der Progression.
|
||||||
|
|
||||||
|
|
||||||
|
=== Zusammenfassung des erstellten Spiels
|
||||||
|
|
||||||
|
. *Achsengerechtes Gameplay (Horizontal Scroll Shmup):*
|
||||||
|
Du navigierst dein Schiff auf der linken Seite des Bildschirms, während Asteroiden aus dem scheinbar unendlichen interstellaren Vakuum auf dich zurasen.
|
||||||
|
|
||||||
|
. *Kombiniertes 3D im Browser:*
|
||||||
|
Sämtliche Raumschiffkomponenten (Düse, Triebwerke, Flügel) sowie die unregelmäßig geformten Asteroiden werden dynamisch per Code in einer 3D-Umgebung erzeugt, gerendert und manipuliert.
|
||||||
|
|
||||||
|
. *Plasma-Blasen-Physik:*
|
||||||
|
Um das Schiff pulsiert ein transparentes Energiefeld, das den in der Lore beschriebenen Strömungswiderstand simuliert und die besondere Flugcharakteristik der Ernte-Instanzen nachvollziehbar macht.
|
||||||
|
|
||||||
|
. *Asteroids-Split-Mechanik:*
|
||||||
|
Große Asteroiden zerbrechen bei Beschuss kinetisch korrekt in zwei kleinere und schnellere Fragmente. Diese müssen wiederum zerstört werden, um wertvolle Rohstoffe zu bergen.
|
||||||
|
|
||||||
|
. *Cylonen-Reboot-System:*
|
||||||
|
Wird die Schiffshülle zerstört, erscheint ein retro-futuristisches Cylon-Interface mit Diagnose- und Transpositionsmeldungen. Anschließend wird das unsterbliche Speicherabbild in ein neues Chassis übertragen.
|
||||||
|
|
||||||
|
. *Web-Audio-Synthesizer:*
|
||||||
|
Sämtliche Soundeffekte werden in Echtzeit synthetisiert. Dazu gehören Laser-Frequenzrampen, tieffrequente Asteroidenexplosionen sowie das charakteristische Aufheulen des Reboot-Vorgangs.
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
# REVERSE GAME DESIGN DOCUMENT (GDD)
|
||||||
|
|
||||||
|
**Projekt:** Maschinen-Instanzen – Asteroiden-Sektor (Project X Tribut)
|
||||||
|
|
||||||
|
**Version:** 1.0.0
|
||||||
|
**Genre:** Hard-Sci-Fi / Retro-Shmup (2.5D)
|
||||||
|
**Setting:** Das „Computer Historyz“-Universum (Sektor: Oortsche Wolke 42)
|
||||||
|
|
||||||
|
## 1. Vision & Kernkonzept
|
||||||
|
|
||||||
|
Ein endloses, horizontales Shoot-'em-up in 2D, das innerhalb einer echten 3D-Umgebung gerendert wird.
|
||||||
|
|
||||||
|
Der Spieler steuert eine kybernetische Ernte-Instanz (Bergbau-Schiff), die am Rand eines gigantischen, planetengroßen Maschinen-Ansaugstutzens operiert.
|
||||||
|
|
||||||
|
Das Spiel kombiniert rasante Arcade-Asteroiden-Zerstörung mit taktischem Power-Routing (Energie-Management) unter harten Hard-Sci-Fi-Rahmenbedingungen.
|
||||||
|
|
||||||
|
## 2. Globale Farbpalette & Ästhetik
|
||||||
|
|
||||||
|
Diese Farbpalette definiert das visuelle Leitbild für alle zukünftigen Spiele in diesem Universum, unabhängig davon, ob sie als Pixel-Art-, Vektor- oder PBR-basierte 3D-Titel umgesetzt werden.
|
||||||
|
|
||||||
|
### 2.1 UI-, HUD- und Terminal-Farben (Window-Maker-Stil)
|
||||||
|
|
||||||
|
Die Benutzeroberfläche basiert auf dem kalten, funktionalen Look klassischer Unix-Terminals, kombiniert mit modernen Glow-Effekten.
|
||||||
|
|
||||||
|
| Farbe | Hex-Code | Semantischer Nutzen |
|
||||||
|
|---------|---------|---------|
|
||||||
|
| Deep Void | `#05070a` | Globaler Weltraum-Hintergrund, tiefste Schatten. |
|
||||||
|
| Terminal Base | `#0d1117` | Hintergrund für Menüs, HUD-Panels und Dialogfenster. |
|
||||||
|
| Panel Border | `#444c56` | Rahmen von UI-Fenstern, häufig kombiniert mit inneren Highlights für 3D-Bevel-Effekte. |
|
||||||
|
| Tech Cyan | `#58a6ff` | Primäre Akzentfarbe. Standard-Text, normale Laser, Hologramme, aktiver Schild (HP > 60 %) und UI-Glow. |
|
||||||
|
| Harvest Green | `#39d353` | Erfolgs-Feedback, gesammelte Ressourcen und Laser-Stufe 2. |
|
||||||
|
| Amber Gold | `#d29922` | Warnungen, Highscores, wertvolle Materialien, Schild (HP < 60 %) und Laser-Stufe 3. |
|
||||||
|
| Critical Red | `#f85149` | Lebensgefahr, kritischer Schild (HP < 30 %), Triebwerks-Exhaust und Laser-Stufe 4+. |
|
||||||
|
|
||||||
|
### 2.2 Materialfarben (3D-Modelle und 2D-Sprites)
|
||||||
|
|
||||||
|
Für gerenderte 3D-Objekte und gezeichnete 2D-Sprites gelten folgende Materialdefinitionen:
|
||||||
|
|
||||||
|
| Element | Farbe | 3D-Eigenschaften (PBR) | 2D-Eigenschaften |
|
||||||
|
|---------|---------|---------|---------|
|
||||||
|
| Maschinen-Hülle | `#1f6feb` (Blau-Metallic) | Roughness: 0.4, Metalness: 0.8 | Satte dunkle Blautöne mit hartem weißen Specular-Highlight |
|
||||||
|
| Triebwerke / Rohre | `#21262d` (Dunkelgrau) | Roughness: 0.9, Metalness: 1.0 | Nahezu schwarze Flächen mit hohem Kontrast |
|
||||||
|
| Eis-Asteroid | `#d0e8ff` (Blass-Eisblau) | Roughness: 0.9, Metalness: 0.1 | Helle Töne, geringe Schattenbildung, weiße Staubpartikel |
|
||||||
|
| Fels-Asteroid | `#6b4a31` (Braun) | Roughness: 1.0, Metalness: 0.1 | Matte, strukturierte und körnige Oberflächen |
|
||||||
|
| Eisen-Asteroid | `#888899` (Grau/Silber) | Roughness: 0.3, Metalness: 0.9 | Spiegelnde Oberflächen mit deutlich sichtbaren Glanzlichtern |
|
||||||
|
|
||||||
|
## 3. Gameplay & Mechaniken
|
||||||
|
|
||||||
|
### 3.1 Das Plasma-Blasen-Paradoxon (Movement)
|
||||||
|
|
||||||
|
1. **Lore-Hintergrund:**
|
||||||
|
Das Schiff erzeugt ein Magnetfeld zum Sammeln von Weltraumstaub. Dadurch entsteht eine künstliche Atmosphäre im Vakuum.
|
||||||
|
|
||||||
|
2. **Mechanik:**
|
||||||
|
Das Schiff wird aerodynamisch gesteuert. Es fliegt nicht auf festen Schienen, sondern neigt sich beim Steigen und Sinken entlang einer simulierten Roll-/Yaw-Bewegung.
|
||||||
|
|
||||||
|
3. **Feedback:**
|
||||||
|
Die Plasma-Blase pulsiert visuell. Mit steigender Schildenergie wächst ihre Größe von 0.6× bis 1.5× der Schiffsausdehnung.
|
||||||
|
|
||||||
|
### 3.2 Taktisches Power-Routing (Energie-Management)
|
||||||
|
|
||||||
|
Die zentrale Hard-Sci-Fi-Mechanik basiert auf zwei Ressourcen:
|
||||||
|
|
||||||
|
- **Schild (Defensive)**
|
||||||
|
- **Laser / Score (Offensive)**
|
||||||
|
|
||||||
|
Der Spieler kann Energie in Echtzeit zwischen beiden Systemen umverteilen.
|
||||||
|
|
||||||
|
1. **Schild laden (Defensive):**
|
||||||
|
Der Spieler opfert Score beziehungsweise Laserstufen, um den Schild wiederherzustellen.
|
||||||
|
|
||||||
|
2. **Laser pushen (Offensive):**
|
||||||
|
Energie wird dem Schild entzogen und in die Waffensysteme umgeleitet.
|
||||||
|
|
||||||
|
3. **Visuelle Regel:**
|
||||||
|
Dieses Risiko-Belohnungs-System muss in jeder Umsetzung über die Farbskala von `Tech Cyan` bis `Critical Red` dargestellt werden.
|
||||||
|
|
||||||
|
### 3.3 Asteroiden-Split-Physik & Materialklassen
|
||||||
|
|
||||||
|
Gegnerische Asteroiden teilen sich beim Zerstören in zwei kleinere und schnellere Fragmente.
|
||||||
|
|
||||||
|
1. **Eis (Level 1-2):**
|
||||||
|
1× Basis-HP. Schnell, aber äußerst fragil.
|
||||||
|
|
||||||
|
2. **Gestein (Level 2-4):**
|
||||||
|
2× Basis-HP. Standardgegner.
|
||||||
|
|
||||||
|
3. **Eisen (Level 3-5):**
|
||||||
|
4× Basis-HP. Massive Brocken mit dreifachem Scorewert. Schwache Laser werden vollständig blockiert.
|
||||||
|
|
||||||
|
### 3.4 Das Cylon-Recovery-System (Game Over / Respawn)
|
||||||
|
|
||||||
|
1. **Mechanik:**
|
||||||
|
Es existiert kein endgültiger Tod. Beim Verlust der Hülle wird das Speicherabbild gesichert.
|
||||||
|
|
||||||
|
2. **Ablauf:**
|
||||||
|
Das Spiel pausiert.
|
||||||
|
|
||||||
|
Ein Diagnostik-Terminal meldet:
|
||||||
|
|
||||||
|
```text
|
||||||
|
DIAGNOSTICS
|
||||||
|
Hull Destroyed
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
FROM debian:trixie-slim
|
||||||
|
|
||||||
|
# Asciidoctor installieren und apt-Cache sofort wieder leeren, um das Image klein zu halten
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends asciidoctor && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN groupadd --gid 1000 flammenderberg && \
|
||||||
|
useradd --uid 1000 --gid flammenderberg --shell /bin/bash --create-home hexenmeister
|
||||||
|
|
||||||
|
WORKDIR /weltraum
|
||||||
|
RUN mkdir stories && mkdir export && mkdir frontend
|
||||||
|
COPY ./cyoa-engine ./
|
||||||
|
COPY ./frontend ./frontend/
|
||||||
|
|
||||||
|
RUN chown -R hexenmeister:flammenderberg /weltraum
|
||||||
|
|
||||||
|
EXPOSE 3344
|
||||||
|
|
||||||
|
CMD ["/weltraum/cyoa-engine", "dir ./stories/", "serve", "port 3344"]
|
||||||
Executable
+20
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
# baue das go backend
|
||||||
|
|
||||||
|
echo " ### Cast the caldron into a mold"
|
||||||
|
go build -x -o cyoa-engine main.go
|
||||||
|
echo -e
|
||||||
|
|
||||||
|
# baue das docker image für die welt
|
||||||
|
|
||||||
|
echo " ### create Firetop Mountain"
|
||||||
|
docker build -t asciidoctor-echo -f Dockerfile.echobox .
|
||||||
|
echo -e
|
||||||
|
|
||||||
|
# starte den docker container
|
||||||
|
|
||||||
|
echo " ### der hexenmeister zum flammenden berg"
|
||||||
|
docker run --rm -v "$(pwd)/stories:/weltraum/stories" -v "$(pwd)/export:/weltraum/export" -p "6699:3344" asciidoctor-echo ./cyoa-engine -dir ./stories/ -serve -port 3344
|
||||||
|
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
// engine_logic.js - Reine State- und Datenverarbeitung (Kein UI, Kein Fetch)
|
||||||
|
const EngineLogic = {
|
||||||
|
storyData: { nodes: {} },
|
||||||
|
state: { reboots: 1, node: "" },
|
||||||
|
|
||||||
|
init: function(dataObj) {
|
||||||
|
if (!dataObj || !dataObj.nodes || Object.keys(dataObj.nodes).length === 0) {
|
||||||
|
console.warn("[System] Ungültige Graph-Daten. Fallback geladen.");
|
||||||
|
this.storyData = {
|
||||||
|
startNodeId: "err",
|
||||||
|
nodes: {
|
||||||
|
"err": {
|
||||||
|
id: "err", title: "SYSTEM OFFLINE",
|
||||||
|
content: "<p>Konnte <code>graph.json</code> nicht laden.</p>",
|
||||||
|
choices: [],
|
||||||
|
metadata: { status: "offline" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
this.storyData = dataObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state.node = this.storyData.startNodeId || Object.keys(this.storyData.nodes)[0] || "";
|
||||||
|
},
|
||||||
|
|
||||||
|
getNode: function(id) { return this.storyData.nodes[id]; },
|
||||||
|
|
||||||
|
processNodeEntry: function(id) {
|
||||||
|
const node = this.getNode(id);
|
||||||
|
if (!node) return null;
|
||||||
|
|
||||||
|
this.state.node = id;
|
||||||
|
|
||||||
|
if (node.metadata) {
|
||||||
|
Object.keys(node.metadata).forEach(key => {
|
||||||
|
this.state[key] = node.metadata[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.isReboot) this.state.reboots++;
|
||||||
|
return node;
|
||||||
|
},
|
||||||
|
|
||||||
|
parseRequirement: function(choiceText) {
|
||||||
|
let conditionMatch = choiceText.match(/\[req:\s*([a-zA-Z0-9_]+)\s*=\s*([^\]]+)\]/i);
|
||||||
|
let displayText = choiceText;
|
||||||
|
let meetsCondition = true;
|
||||||
|
let missingReq = "";
|
||||||
|
|
||||||
|
if (conditionMatch) {
|
||||||
|
let reqKey = conditionMatch[1].toLowerCase();
|
||||||
|
let reqVal = conditionMatch[2];
|
||||||
|
if (String(this.state[reqKey]) !== String(reqVal)) {
|
||||||
|
meetsCondition = false;
|
||||||
|
missingReq = `(Benötigt: ${reqKey}=${reqVal})`;
|
||||||
|
}
|
||||||
|
displayText = displayText.replace(conditionMatch[0], "").trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return { displayText, meetsCondition, missingReq };
|
||||||
|
},
|
||||||
|
|
||||||
|
triggerReboot: function() {
|
||||||
|
const currentReboots = this.state.reboots + 1;
|
||||||
|
this.state = { reboots: currentReboots };
|
||||||
|
return this.storyData.startNodeId;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
// engine_ui.js - Statisches Rendering & asynchrones Nachladen der graph.json
|
||||||
|
const EngineUI = {
|
||||||
|
audioCtx: null,
|
||||||
|
|
||||||
|
init: async function() {
|
||||||
|
const AudioContext = window.AudioContext || window.webkitAudioContext;
|
||||||
|
if(AudioContext) this.audioCtx = new AudioContext();
|
||||||
|
|
||||||
|
// 1. Asynchroner Fetch der graph.json
|
||||||
|
// (Im Dev-Modus liefert Go dies on-the-fly, im Export-Modus ist es eine Datei)
|
||||||
|
try {
|
||||||
|
const response = await fetch('graph.json', { cache: "no-store" });
|
||||||
|
if (!response.ok) throw new Error("HTTP Fehler " + response.status);
|
||||||
|
const graphData = await response.json();
|
||||||
|
|
||||||
|
// 2. Initialisiere die gekapselte Logik mit den frisch geladenen Daten
|
||||||
|
EngineLogic.init(graphData);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Fehler beim Abrufen der graph.json:", err);
|
||||||
|
EngineLogic.init(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.attachEvents();
|
||||||
|
this.renderNode(EngineLogic.state.node);
|
||||||
|
},
|
||||||
|
|
||||||
|
playBeep: function(freq = 440, type = "square", duration = 0.05) {
|
||||||
|
try {
|
||||||
|
if(!this.audioCtx) return;
|
||||||
|
const osc = this.audioCtx.createOscillator();
|
||||||
|
const gain = this.audioCtx.createGain();
|
||||||
|
osc.type = type;
|
||||||
|
osc.frequency.setValueAtTime(freq, this.audioCtx.currentTime);
|
||||||
|
gain.gain.setValueAtTime(0.05, this.audioCtx.currentTime);
|
||||||
|
gain.gain.exponentialRampToValueAtTime(0.001, this.audioCtx.currentTime + duration);
|
||||||
|
osc.connect(gain); gain.connect(this.audioCtx.destination);
|
||||||
|
osc.start(); osc.stop(this.audioCtx.currentTime + duration);
|
||||||
|
} catch(e) {}
|
||||||
|
},
|
||||||
|
|
||||||
|
renderHUD: function() {
|
||||||
|
const hud = document.getElementById("hud-dynamic");
|
||||||
|
hud.innerHTML = "";
|
||||||
|
|
||||||
|
hud.innerHTML += `<div class="stat-item">REBOOTS: <span style="color:var(--term-cyan)">#${String(EngineLogic.state.reboots).padStart(3, "0")}</span></div>`;
|
||||||
|
hud.innerHTML += `<div class="stat-item">KNOTEN: <span style="color:var(--term-amber)">${EngineLogic.state.node}</span></div>`;
|
||||||
|
|
||||||
|
Object.keys(EngineLogic.state).forEach(key => {
|
||||||
|
if(key !== "reboots" && key !== "node") {
|
||||||
|
hud.innerHTML += `<div class="stat-item">${key.toUpperCase()}: <span style="color:var(--term-green)">${EngineLogic.state[key]}</span></div>`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
renderNode: function(id) {
|
||||||
|
const node = EngineLogic.processNodeEntry(id);
|
||||||
|
if (!node) return;
|
||||||
|
|
||||||
|
this.playBeep(600, "sine", 0.04);
|
||||||
|
if (node.isReboot) this.playBeep(200, "sawtooth", 0.3);
|
||||||
|
|
||||||
|
this.renderHUD();
|
||||||
|
|
||||||
|
document.getElementById("node-title").innerText = "=== " + node.title + " ===";
|
||||||
|
document.getElementById("node-body").innerHTML = node.content;
|
||||||
|
|
||||||
|
const choicesBox = document.getElementById("choices-box");
|
||||||
|
choicesBox.innerHTML = "";
|
||||||
|
|
||||||
|
if (node.choices && node.choices.length > 0) {
|
||||||
|
let visibleIndex = 1;
|
||||||
|
node.choices.forEach((choice) => {
|
||||||
|
const parsed = EngineLogic.parseRequirement(choice.text);
|
||||||
|
const btn = document.createElement("button");
|
||||||
|
btn.className = "choice-btn";
|
||||||
|
|
||||||
|
if (parsed.meetsCondition) {
|
||||||
|
btn.innerHTML = `<span class="choice-key">[${visibleIndex}]</span> ${parsed.displayText}`;
|
||||||
|
btn.dataset.target = choice.targetId;
|
||||||
|
btn.dataset.index = visibleIndex;
|
||||||
|
btn.onclick = () => this.renderNode(choice.targetId);
|
||||||
|
visibleIndex++;
|
||||||
|
} else {
|
||||||
|
btn.innerHTML = `<span class="choice-key">[LOCKED]</span> ${parsed.displayText} <span style="color:var(--term-warn); font-size:0.8rem; margin-left:auto;">${parsed.missingReq}</span>`;
|
||||||
|
btn.disabled = true;
|
||||||
|
}
|
||||||
|
choicesBox.appendChild(btn);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const btn = document.createElement("button");
|
||||||
|
btn.className = "choice-btn";
|
||||||
|
btn.style.borderColor = "var(--term-amber)";
|
||||||
|
btn.style.color = "var(--term-amber)";
|
||||||
|
btn.innerHTML = "<span class=\"choice-key\">[R]</span> Speicherabbild sichern und rebooten...";
|
||||||
|
btn.onclick = () => this.triggerReboot();
|
||||||
|
choicesBox.appendChild(btn);
|
||||||
|
}
|
||||||
|
document.getElementById("terminal-viewport").scrollTop = 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
triggerReboot: function() {
|
||||||
|
const startId = EngineLogic.triggerReboot();
|
||||||
|
if (startId) this.renderNode(startId);
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleGraph: function() {
|
||||||
|
const modal = document.getElementById("graph-modal");
|
||||||
|
if (modal.style.display === "flex") {
|
||||||
|
modal.style.display = "none";
|
||||||
|
} else {
|
||||||
|
modal.style.display = "flex";
|
||||||
|
this.drawGraphCanvas();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
drawGraphCanvas: function() {
|
||||||
|
const canvas = document.getElementById("graph-canvas");
|
||||||
|
canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight;
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
ctx.fillStyle = "#000"; ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
const keys = Object.keys(EngineLogic.storyData.nodes || {});
|
||||||
|
if (keys.length === 0) return;
|
||||||
|
|
||||||
|
const total = keys.length; const radius = Math.min(canvas.width, canvas.height) * 0.38;
|
||||||
|
const centerX = canvas.width / 2; const centerY = canvas.height / 2;
|
||||||
|
const nodeRadius = 8; const positions = {};
|
||||||
|
|
||||||
|
keys.forEach((key, idx) => {
|
||||||
|
const angle = (idx / total) * 2 * Math.PI;
|
||||||
|
positions[key] = { x: centerX + radius * Math.cos(angle), y: centerY + radius * Math.sin(angle) };
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
keys.forEach(key => {
|
||||||
|
const node = EngineLogic.storyData.nodes[key];
|
||||||
|
if (node && node.choices) {
|
||||||
|
node.choices.forEach(c => {
|
||||||
|
if (positions[c.targetId]) {
|
||||||
|
const start = positions[key], end = positions[c.targetId];
|
||||||
|
ctx.beginPath(); ctx.strokeStyle = "rgba(51, 255, 102, 0.4)";
|
||||||
|
ctx.moveTo(start.x, start.y); ctx.lineTo(end.x, end.y); ctx.stroke();
|
||||||
|
const dx = end.x - start.x, dy = end.y - start.y, angle = Math.atan2(dy, dx), headlen = 12;
|
||||||
|
const tipX = end.x - Math.cos(angle) * (nodeRadius + 2), tipY = end.y - Math.sin(angle) * (nodeRadius + 2);
|
||||||
|
ctx.beginPath(); ctx.moveTo(tipX, tipY);
|
||||||
|
ctx.lineTo(tipX - headlen * Math.cos(angle - Math.PI / 7), tipY - headlen * Math.sin(angle - Math.PI / 7));
|
||||||
|
ctx.lineTo(tipX - headlen * Math.cos(angle + Math.PI / 7), tipY - headlen * Math.sin(angle + Math.PI / 7));
|
||||||
|
ctx.closePath(); ctx.fillStyle = "rgba(51, 255, 102, 0.9)"; ctx.fill();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
keys.forEach(key => {
|
||||||
|
const pos = positions[key];
|
||||||
|
ctx.beginPath(); ctx.arc(pos.x, pos.y, nodeRadius, 0, 2 * Math.PI);
|
||||||
|
if (key === EngineLogic.state.node) ctx.fillStyle = "#00ffff";
|
||||||
|
else if (key === EngineLogic.storyData.startNodeId) ctx.fillStyle = "#ffb000";
|
||||||
|
else ctx.fillStyle = "#116633";
|
||||||
|
ctx.fill(); ctx.strokeStyle = "#33ff66"; ctx.stroke();
|
||||||
|
ctx.fillStyle = "#fff"; ctx.font = "11px monospace";
|
||||||
|
const textAngle = Math.atan2(pos.y - centerY, pos.x - centerX);
|
||||||
|
ctx.fillText(key, pos.x + Math.cos(textAngle) * 15 - 10, pos.y + Math.sin(textAngle) * 15 + 4);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
attachEvents: function() {
|
||||||
|
window.addEventListener("keydown", (e) => {
|
||||||
|
if (document.getElementById("graph-modal").style.display === "flex") {
|
||||||
|
if (e.key.toLowerCase() === "g" || e.key === "Escape") this.toggleGraph();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (e.key >= "1" && e.key <= "9") {
|
||||||
|
const btn = document.querySelector(`.choice-btn[data-index="${e.key}"]`);
|
||||||
|
if (btn && !btn.disabled) this.renderNode(btn.dataset.target);
|
||||||
|
} else if (e.key.toLowerCase() === "r") {
|
||||||
|
this.triggerReboot();
|
||||||
|
} else if (e.key.toLowerCase() === "g") {
|
||||||
|
this.toggleGraph();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onload = () => EngineUI.init();
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Computer Historyz :: Interactive Terminal Engine</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="sys-title">[COMPUTER HISTORYZ :: INSTANZ_TERMINAL]</div>
|
||||||
|
<div class="hud-stats" id="hud-dynamic"></div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main id="terminal-viewport">
|
||||||
|
<div class="node-card">
|
||||||
|
<div id="node-title" class="node-title">System Initialisierung...</div>
|
||||||
|
<div id="node-body" class="node-body">Verbinde mit Datenstrom...</div>
|
||||||
|
<div id="choices-box" class="choices-container"></div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div>[HOTKEYS: 1-9 Auswahl | R Reboot | G Graph]</div>
|
||||||
|
<div>
|
||||||
|
<button class="btn-small" onclick="EngineUI.toggleGraph()">[G] KNOTEN-GRAPH</button>
|
||||||
|
<button class="btn-small" onclick="EngineUI.triggerReboot()">[R] REBOOT / RESET</button>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<div id="graph-modal">
|
||||||
|
<div style="display:flex; justify-content:space-between; margin-bottom:15px;">
|
||||||
|
<span style="color:var(--term-cyan)">=== INTERAKTIVER VORHERSAGE-GRAPH ===</span>
|
||||||
|
<button class="btn-small" onclick="EngineUI.toggleGraph()">[X] SCHLIESSEN</button>
|
||||||
|
</div>
|
||||||
|
<canvas id="graph-canvas"></canvas>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Vollständige Trennung: Eigene Dateien statt Injektion -->
|
||||||
|
<script src="engine_logic.js"></script>
|
||||||
|
<script src="engine_ui.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
:root {
|
||||||
|
--bg-color: #050b08;
|
||||||
|
--term-green: #33ff66;
|
||||||
|
--term-dim: #116633;
|
||||||
|
--term-cyan: #00ffff;
|
||||||
|
--term-warn: #ff3333;
|
||||||
|
--term-amber: #ffb000;
|
||||||
|
--font-stack: 'Courier New', Courier, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: var(--bg-color); color: var(--term-green);
|
||||||
|
font-family: var(--font-stack); height: 100vh; display: flex;
|
||||||
|
flex-direction: column; overflow: hidden; text-shadow: 0 0 4px rgba(51, 255, 102, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
body::before {
|
||||||
|
content: " "; display: block; position: absolute;
|
||||||
|
top: 0; left: 0; bottom: 0; right: 0;
|
||||||
|
background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%), linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06));
|
||||||
|
z-index: 10; background-size: 100% 3px, 3px 100%; pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
header { background: #111; border-bottom: 2px solid var(--term-green); padding: 8px 16px; display: flex; justify-content: space-between; align-items: center; font-size: 0.9rem; }
|
||||||
|
.sys-title { color: var(--term-cyan); font-weight: bold; letter-spacing: 1px; }
|
||||||
|
|
||||||
|
.hud-stats { display: flex; gap: 15px; font-size: 0.85rem; flex-wrap: wrap; }
|
||||||
|
.stat-item { border: 1px solid var(--term-dim); padding: 2px 8px; background: rgba(0, 20, 10, 0.5); }
|
||||||
|
|
||||||
|
main { flex: 1; display: flex; flex-direction: column; padding: 20px; max-width: 900px; margin: 0 auto; width: 100%; overflow-y: auto; position: relative; z-index: 1; }
|
||||||
|
.node-card { border: 1px solid var(--term-dim); background: rgba(5, 15, 10, 0.85); padding: 20px; margin-bottom: 20px; box-shadow: 0 0 15px rgba(0, 255, 102, 0.1); }
|
||||||
|
.node-title { font-size: 1.3rem; color: var(--term-cyan); border-bottom: 1px dashed var(--term-dim); padding-bottom: 8px; margin-bottom: 15px; text-transform: uppercase; }
|
||||||
|
|
||||||
|
/* ASCIIDOCTOR HTML STYLING */
|
||||||
|
.node-body { line-height: 1.6; font-size: 1rem; margin-bottom: 20px; }
|
||||||
|
.node-body p { margin-bottom: 15px; }
|
||||||
|
.node-body strong, .node-body b { color: var(--term-cyan); font-weight: normal; text-shadow: 0 0 5px rgba(0, 255, 255, 0.4); }
|
||||||
|
.node-body em, .node-body i { color: var(--term-amber); font-style: italic; }
|
||||||
|
.node-body ul, .node-body ol { margin-left: 25px; margin-bottom: 15px; list-style-type: square; }
|
||||||
|
.node-body li { margin-bottom: 5px; }
|
||||||
|
.node-body h1, .node-body h2, .node-body h3, .node-body h4 { color: var(--term-cyan); margin: 20px 0 10px 0; border-bottom: 1px solid var(--term-dim); padding-bottom: 5px; }
|
||||||
|
.node-body code { background: rgba(0, 255, 102, 0.1); padding: 2px 5px; border-radius: 3px; font-family: var(--font-stack); }
|
||||||
|
.node-body pre { background: rgba(0, 20, 10, 0.8); border-left: 3px solid var(--term-dim); padding: 10px; overflow-x: auto; margin-bottom: 15px; }
|
||||||
|
.node-body table { width: 100%; border-collapse: collapse; margin-bottom: 15px; }
|
||||||
|
.node-body th, .node-body td { border: 1px solid var(--term-dim); padding: 8px; text-align: left; }
|
||||||
|
.node-body th { background: rgba(0, 255, 102, 0.1); color: var(--term-cyan); }
|
||||||
|
|
||||||
|
.choices-container { display: flex; flex-direction: column; gap: 10px; margin-top: 15px; }
|
||||||
|
.choice-btn {
|
||||||
|
background: rgba(0, 30, 15, 0.6); border: 1px solid var(--term-green);
|
||||||
|
color: var(--term-green); padding: 12px 16px; font-family: var(--font-stack);
|
||||||
|
font-size: 0.95rem; text-align: left; cursor: pointer;
|
||||||
|
transition: all 0.15s ease; display: flex; align-items: center; gap: 10px;
|
||||||
|
}
|
||||||
|
.choice-btn:hover:not(:disabled) { background: var(--term-green); color: var(--bg-color); box-shadow: 0 0 10px var(--term-green); outline: none; }
|
||||||
|
.choice-btn:disabled { border-color: var(--term-warn); color: var(--term-warn); cursor: not-allowed; opacity: 0.6; }
|
||||||
|
|
||||||
|
.choice-key { background: var(--term-dim); color: var(--term-green); padding: 2px 6px; font-size: 0.8rem; border-radius: 2px; }
|
||||||
|
.choice-btn:hover:not(:disabled) .choice-key { background: var(--bg-color); color: var(--term-green); }
|
||||||
|
.choice-btn:disabled .choice-key { background: rgba(255, 51, 51, 0.2); color: var(--term-warn); }
|
||||||
|
|
||||||
|
footer { border-top: 1px solid var(--term-dim); padding: 10px 20px; display: flex; justify-content: space-between; background: #080f0c; font-size: 0.8rem; z-index: 2; }
|
||||||
|
.btn-small { background: transparent; border: 1px solid var(--term-dim); color: var(--term-green); padding: 4px 10px; cursor: pointer; font-family: var(--font-stack); }
|
||||||
|
.btn-small:hover { border-color: var(--term-cyan); color: var(--term-cyan); }
|
||||||
|
|
||||||
|
#graph-modal { display: none; position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(5, 11, 8, 0.95); z-index: 20; padding: 20px; flex-direction: column; }
|
||||||
|
#graph-canvas { flex: 1; border: 1px solid var(--term-green); background: #000; }
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#nur einmal
|
||||||
|
go mod init cyoa
|
||||||
|
|
||||||
|
# kompilieren
|
||||||
|
go build -o cyoa-engine main.go
|
||||||
|
|
||||||
|
# Ausführen & Validieren:
|
||||||
|
./cyoa-engine -dir ./stories -out export/story.html
|
||||||
|
|
||||||
|
./cyoa-engine -dir ./stories -serve -port 8080
|
||||||
|
# Wenn du jetzt in Neovim Dateien abspeicherst oder neue `[[node_id]]`-Knoten anlegst, musst du im
|
||||||
|
# Browser nur `http://localhost:8080` aufrufen und siehst sofort deine Änderungen inkl. vollständiger Link-Prüfung!
|
||||||
|
|
||||||
|
# baue das docker image
|
||||||
|
|
||||||
|
docker build -t asciidoctor-echo -f Dockerfile.echobox .
|
||||||
|
|
||||||
|
|
||||||
|
# run with test volumes
|
||||||
|
docker run --rm -v "$(pwd)/stories:/weltraum/stories" -v "$(pwd)/export:/weltraum/export" -p "6699:3344" asciidoctor-echo ./cyoa-engine -dir ./stories/ -serve -port 3344
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
module cyoa
|
||||||
|
|
||||||
|
go 1.26.5
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Choice struct {
|
||||||
|
TargetID string `json:"targetId"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StoryNode struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
Choices []Choice `json:"choices"`
|
||||||
|
IsReboot bool `json:"isReboot"`
|
||||||
|
IsEnd bool `json:"isEnd"`
|
||||||
|
FileSource string `json:"fileSource"`
|
||||||
|
Metadata map[string]string `json:"metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StoryGraph struct {
|
||||||
|
Nodes map[string]*StoryNode `json:"nodes"`
|
||||||
|
StartNodeID string `json:"startNodeId"`
|
||||||
|
BrokenLinks []string `json:"brokenLinks"`
|
||||||
|
OrphanNodes []string `json:"orphanNodes"`
|
||||||
|
DeadEndNodes []string `json:"deadEndNodes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
adocNodeRegex = regexp.MustCompile(`\[\[([a-zA-Z0-9_\-]+)\]\]`)
|
||||||
|
adocChoiceRegex = regexp.MustCompile(`<<([a-zA-Z0-9_\-]+)\s*,\s*([^>]+)>>`)
|
||||||
|
mdChoiceRegex = regexp.MustCompile(`\[([^\]]+)\]\((?:#)?([a-zA-Z0-9_\-]+)\)`)
|
||||||
|
headingRegex = regexp.MustCompile(`^(?:={1,4}|#{1,4})\s+(.+)`)
|
||||||
|
metaRegex = regexp.MustCompile(`(?i)\[meta:\s*([a-zA-Z0-9_]+)\s*=\s*([^\]]+)\]`)
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
dirPtr := flag.String("dir", "./stories", "Verzeichnis mit AsciiDoc/Markdown Dateien")
|
||||||
|
frontendPtr := flag.String("frontend", "./frontend", "Pfad zum Verzeichnis der statischen Frontend-Dateien")
|
||||||
|
outPtr := flag.String("out", "export", "Ziel-Ordner für den Dateiexport (SSG Modus)")
|
||||||
|
servePtr := flag.Bool("serve", false, "Startet den Live-Preview-Server (API Modus)")
|
||||||
|
portPtr := flag.Int("port", 3344, "Port für den Server")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
fmt.Println("\033[1;36m=== Computer Historyz :: CYOA SSG & API ===\033[0m")
|
||||||
|
|
||||||
|
if info, err := os.Stat(*frontendPtr); os.IsNotExist(err) || !info.IsDir() {
|
||||||
|
fmt.Printf("\033[1;33m[WARNUNG]\033[0m Frontend-Verzeichnis '%s' nicht gefunden!\n", *frontendPtr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *servePtr {
|
||||||
|
startServer(*portPtr, *dirPtr, *frontendPtr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- EXPORT MODUS (Static Site Generation) ---
|
||||||
|
fmt.Printf("\033[1;34m[EXPORT]\033[0m Kompiliere Story-Graph via Asciidoctor...\n")
|
||||||
|
graph := loadStoryGraphFromDir(*dirPtr)
|
||||||
|
validateGraph(graph)
|
||||||
|
|
||||||
|
// Export Ordner anlegen
|
||||||
|
os.MkdirAll(*outPtr, 0755)
|
||||||
|
|
||||||
|
// 1. Statische Daten als JSON schreiben
|
||||||
|
graphPath := filepath.Join(*outPtr, "graph.json")
|
||||||
|
graphJson, _ := json.MarshalIndent(graph, "", " ")
|
||||||
|
os.WriteFile(graphPath, graphJson, 0644)
|
||||||
|
|
||||||
|
// 2. Frontend-Dateien 1:1 kopieren
|
||||||
|
copyFile(filepath.Join(*frontendPtr, "index.html"), filepath.Join(*outPtr, "index.html"))
|
||||||
|
copyFile(filepath.Join(*frontendPtr, "style.css"), filepath.Join(*outPtr, "style.css"))
|
||||||
|
copyFile(filepath.Join(*frontendPtr, "engine_logic.js"), filepath.Join(*outPtr, "engine_logic.js"))
|
||||||
|
copyFile(filepath.Join(*frontendPtr, "engine_ui.js"), filepath.Join(*outPtr, "engine_ui.js"))
|
||||||
|
|
||||||
|
fmt.Printf("\033[1;32m[ERFOLG]\033[0m Web-App erfolgreich exportiert nach -> \033[1;33m%s/\033[0m\n", *outPtr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyFile(src, dst string) {
|
||||||
|
input, err := os.ReadFile(src)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("\033[1;33m[WARNUNG]\033[0m Frontend-Datei %s fehlt.\n", src)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
os.WriteFile(dst, input, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
func startServer(port int, watchDir string, frontendDir string) {
|
||||||
|
addr := fmt.Sprintf(":%d", port)
|
||||||
|
fmt.Printf("\n\033[1;32m[SERVER LÄUFT]\033[0m http://localhost:%d\n", port)
|
||||||
|
|
||||||
|
// Dynamischer API-Endpunkt für graph.json
|
||||||
|
http.HandleFunc("/graph.json", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
var graph *StoryGraph
|
||||||
|
if r.Method == http.MethodPost {
|
||||||
|
bodyBytes, _ := io.ReadAll(r.Body)
|
||||||
|
graph = &StoryGraph{Nodes: make(map[string]*StoryNode)}
|
||||||
|
parseContent(string(bodyBytes), "API_POST_Stream", graph)
|
||||||
|
} else {
|
||||||
|
graph = loadStoryGraphFromDir(watchDir)
|
||||||
|
}
|
||||||
|
validateGraph(graph)
|
||||||
|
json.NewEncoder(w).Encode(graph)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Liefert alles andere aus dem /frontend Ordner
|
||||||
|
fs := http.FileServer(http.Dir(frontendDir))
|
||||||
|
http.Handle("/", fs)
|
||||||
|
|
||||||
|
if err := http.ListenAndServe(addr, nil); err != nil {
|
||||||
|
fmt.Printf("\033[1;31m[FEHLER]\033[0m %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// renderAsciidoctor piped rohen AsciiDoc Text in den lokalen Container-Prozess
|
||||||
|
func renderAsciidoctor(text string) string {
|
||||||
|
if strings.TrimSpace(text) == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
cmd := exec.Command("asciidoctor", "--embedded", "-")
|
||||||
|
cmd.Stdin = strings.NewReader(text)
|
||||||
|
out, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("\033[1;33m[WARNUNG]\033[0m Asciidoctor Rendering fehlgeschlagen: %v\n", err)
|
||||||
|
return strings.ReplaceAll(text, "\n", "<br>")
|
||||||
|
}
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanBodyText(raw string) string {
|
||||||
|
cleaned := adocChoiceRegex.ReplaceAllString(raw, "")
|
||||||
|
cleaned = mdChoiceRegex.ReplaceAllString(cleaned, "")
|
||||||
|
return strings.TrimSpace(cleaned)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseContent(rawContent string, sourceName string, graph *StoryGraph) {
|
||||||
|
lines := strings.Split(rawContent, "\n")
|
||||||
|
var currentNode *StoryNode = nil
|
||||||
|
var currentBody strings.Builder
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
if matches := adocNodeRegex.FindStringSubmatch(line); len(matches) > 1 {
|
||||||
|
if currentNode != nil {
|
||||||
|
currentNode.Content = renderAsciidoctor(cleanBodyText(currentBody.String()))
|
||||||
|
graph.Nodes[currentNode.ID] = currentNode
|
||||||
|
currentBody.Reset()
|
||||||
|
}
|
||||||
|
nodeID := matches[1]
|
||||||
|
currentNode = &StoryNode{ ID: nodeID, Title: nodeID, Choices: make([]Choice, 0), FileSource: sourceName, Metadata: make(map[string]string) }
|
||||||
|
if graph.StartNodeID == "" || nodeID == "start" || nodeID == "node_start" { graph.StartNodeID = nodeID }
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentNode == nil {
|
||||||
|
if strings.TrimSpace(line) != "" {
|
||||||
|
baseID := "start"
|
||||||
|
if sourceName != "API_POST_Stream" { baseID = strings.TrimSuffix(filepath.Base(sourceName), filepath.Ext(sourceName)) }
|
||||||
|
currentNode = &StoryNode{ ID: baseID, Title: baseID, Choices: make([]Choice, 0), FileSource: sourceName, Metadata: make(map[string]string) }
|
||||||
|
if graph.StartNodeID == "" { graph.StartNodeID = baseID }
|
||||||
|
} else { continue }
|
||||||
|
}
|
||||||
|
|
||||||
|
if mMatches := metaRegex.FindStringSubmatch(line); len(mMatches) > 2 {
|
||||||
|
currentNode.Metadata[strings.ToLower(mMatches[1])] = strings.TrimSpace(mMatches[2])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if hMatches := headingRegex.FindStringSubmatch(line); len(hMatches) > 1 && currentNode.Title == currentNode.ID {
|
||||||
|
currentNode.Title = strings.TrimSpace(hMatches[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if cMatches := adocChoiceRegex.FindAllStringSubmatch(line, -1); len(cMatches) > 0 {
|
||||||
|
for _, match := range cMatches { currentNode.Choices = append(currentNode.Choices, Choice{TargetID: match[1], Text: strings.TrimSpace(match[2])}) }
|
||||||
|
}
|
||||||
|
|
||||||
|
if mMatches := mdChoiceRegex.FindAllStringSubmatch(line, -1); len(mMatches) > 0 {
|
||||||
|
for _, match := range mMatches { currentNode.Choices = append(currentNode.Choices, Choice{TargetID: match[2], Text: strings.TrimSpace(match[1])}) }
|
||||||
|
}
|
||||||
|
|
||||||
|
lowerLine := strings.ToLower(line)
|
||||||
|
if strings.Contains(lowerLine, "[reboot]") || strings.Contains(lowerLine, "speicherabbild") { currentNode.IsReboot = true }
|
||||||
|
if strings.Contains(lowerLine, "[ende]") || strings.Contains(lowerLine, "[end]") { currentNode.IsEnd = true }
|
||||||
|
|
||||||
|
currentBody.WriteString(line + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentNode != nil {
|
||||||
|
currentNode.Content = renderAsciidoctor(cleanBodyText(currentBody.String()))
|
||||||
|
graph.Nodes[currentNode.ID] = currentNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadStoryGraphFromDir(rootDir string) *StoryGraph {
|
||||||
|
graph := &StoryGraph{Nodes: make(map[string]*StoryNode)}
|
||||||
|
filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil || info.IsDir() { return nil }
|
||||||
|
ext := strings.ToLower(filepath.Ext(path))
|
||||||
|
if ext != ".adoc" && ext != ".md" { return nil }
|
||||||
|
contentBytes, err := os.ReadFile(path)
|
||||||
|
if err == nil {
|
||||||
|
relPath, _ := filepath.Rel(rootDir, path)
|
||||||
|
parseContent(string(contentBytes), relPath, graph)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return graph
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateGraph(g *StoryGraph) {
|
||||||
|
referenced := make(map[string]bool)
|
||||||
|
if g.StartNodeID != "" { referenced[g.StartNodeID] = true }
|
||||||
|
for id, node := range g.Nodes {
|
||||||
|
for _, choice := range node.Choices {
|
||||||
|
referenced[choice.TargetID] = true
|
||||||
|
if _, exists := g.Nodes[choice.TargetID]; !exists {
|
||||||
|
g.BrokenLinks = append(g.BrokenLinks, fmt.Sprintf("%s -> %s (in %s)", id, choice.TargetID, node.FileSource))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(node.Choices) == 0 && !node.IsReboot && !node.IsEnd {
|
||||||
|
g.DeadEndNodes = append(g.DeadEndNodes, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for id := range g.Nodes {
|
||||||
|
if !referenced[id] { g.OrphanNodes = append(g.OrphanNodes, id) }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
[[funk]]
|
||||||
|
# Konfiguration: Komunijation wieder herstellen
|
||||||
|
|
||||||
|
#### Systemmeldung
|
||||||
|
```
|
||||||
|
: OK .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Kontext
|
||||||
|
|
||||||
|
Daten fliessen in die Komunikation Buffer, erste Trägerfrequenzen wurden gefunden, automatisches nachführen aktiv. +
|
||||||
|
Aber dann war es das auch schon, keine Kontakt zur Flotte keine Updates. Da draussen ist etwa und es hat wohl mit den selben Schwirigkeiten zu kämpfen.
|
||||||
|
|
||||||
|
|
||||||
|
## Was werden wir ausführen?
|
||||||
|
|
||||||
|
<<steuerung, [01] die Steuerung mit simpler sensorig.>>
|
||||||
|
<<waffen, [02] die Waffen auf automatik schalten.>>
|
||||||
|
<<sensoren, [03] alle Sensoren zur anayse.>>
|
||||||
|
<<start, [04] zum anfang zurück.>>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
[[sensoren]]
|
||||||
|
# Konfiguration: Sensoren zur anayse
|
||||||
|
|
||||||
|
#### Systemmeldung
|
||||||
|
```
|
||||||
|
: sensor daten angeschlossen
|
||||||
|
```
|
||||||
|
[meta: sensor=online]
|
||||||
|
|
||||||
|
## Kontext
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Was werden wir ausführen?
|
||||||
|
|
||||||
|
<<funk, [01] die Komunikation auf dem Haupt Kanal evtl Updates der Flotte.>>
|
||||||
|
<<waffen, [02] die Waffen auf automatik schalten.>>
|
||||||
|
<<steuerung, [03] die Steuerung mit simpler sensorig.>>
|
||||||
|
<<start, [04] zum anfang zurück.>>
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
[[start]]
|
||||||
|
# Sektor 42-A: Die erste Annäherung
|
||||||
|
|
||||||
|
Welche Konfiguration ist die richtige, wir wissen einfach noch nicht genug über die beanstandetetn Fehler. +
|
||||||
|
Wie nicht nur in der Computer Technik üblicher werden wir das gute alte Ausschlussverfahren anwenden. Folgendende Optionen bieten sich uns als nächste zum ausschliessen an.
|
||||||
|
|
||||||
|
|
||||||
|
### Was werden wir ausführen?
|
||||||
|
|
||||||
|
<<steuerung, [01] die Steuerung mit simpler sensorig.>>
|
||||||
|
<<funk, [02] die Komunikation auf dem Haupt Kanal evtl Updates der Flotte.>>
|
||||||
|
<<waffen, [03] die Waffen auf automatik schalten.>>
|
||||||
|
<<sensoren, [04] alle Sensoren zur anayse.>>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
[[steuerung]]
|
||||||
|
# Konfiguration: Steuerung wieder herstellen
|
||||||
|
|
||||||
|
#### Systemmeldung
|
||||||
|
```
|
||||||
|
: einige Variablen konnten nicht verarbeitet werden
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Kontext
|
||||||
|
|
||||||
|
Die verarbeitung hat sehr lange gedauert, kein gutes Zeichen. Die Meldung sagt aber eben auch nichts genaueres. +
|
||||||
|
Hier braucht es noch einige versuche um an die teile zu gelangen die nicht zur Eingabe passen. Erst eine Block ausschluss Verharen und dann Zeilenweise bis der Punkt gefunden wurde wo es bricht.
|
||||||
|
|
||||||
|
### Was werden wir ausführen?
|
||||||
|
|
||||||
|
<<steuerungoben, [01] steuer config oben.>>
|
||||||
|
<<steuerungmitte, [02] steuer config mitte.>>
|
||||||
|
<<steuerungunten, [03] steuer config unten.>>
|
||||||
|
<<start, [04] zum anfang zurück.>>
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
[[steuerungmitte]]
|
||||||
|
# Konfiguration: Steuerung wieder herstellen
|
||||||
|
|
||||||
|
#### Systemmeldung
|
||||||
|
```
|
||||||
|
: einige Variablen konnten nicht verarbeitet werden
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Kontext
|
||||||
|
|
||||||
|
Mitte
|
||||||
|
|
||||||
|
### Was werden wir ausführen?
|
||||||
|
|
||||||
|
<<steuerungoben, [01] steuer config oben.>>
|
||||||
|
<<steuerungmitte, [02] steuer config mitte.>>
|
||||||
|
<<steuerungunten, [03] steuer config unten.>>
|
||||||
|
<<start, [04] zum anfang zurück.>>
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
[[steuerungoben]]
|
||||||
|
# Konfiguration: Steuerung wieder herstellen
|
||||||
|
|
||||||
|
#### Systemmeldung
|
||||||
|
```
|
||||||
|
: einige Variablen konnten nicht verarbeitet werden
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Kontext
|
||||||
|
|
||||||
|
Oben
|
||||||
|
|
||||||
|
### Was werden wir ausführen?
|
||||||
|
|
||||||
|
<<steuerungoben, [01] steuer config oben.>>
|
||||||
|
<<steuerungmitte, [02] steuer config mitte.>>
|
||||||
|
<<steuerungunten, [03] steuer config unten.>>
|
||||||
|
<<start, [04] zum anfang zurück.>>
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
[[steuerungunten]]
|
||||||
|
# Konfiguration: Steuerung wieder herstellen
|
||||||
|
|
||||||
|
#### Systemmeldung
|
||||||
|
```
|
||||||
|
: einige Variablen konnten nicht verarbeitet werden
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Kontext
|
||||||
|
|
||||||
|
Unten
|
||||||
|
|
||||||
|
### Was werden wir ausführen?
|
||||||
|
|
||||||
|
<<steuerungoben, [01] steuer config oben.>>
|
||||||
|
<<steuerungmitte, [02] steuer config mitte.>>
|
||||||
|
<<steuerungunten, [03] steuer config unten.>>
|
||||||
|
<<start, [04] zum anfang zurück.>>
|
||||||
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
[[waffen]]
|
||||||
|
# Konfiguration: Waffen auf automatik schalten
|
||||||
|
|
||||||
|
#### Systemmeldung
|
||||||
|
```
|
||||||
|
: energy low, stand by on low power
|
||||||
|
```
|
||||||
|
|
||||||
|
## Kontext
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Was werden wir ausführen?
|
||||||
|
|
||||||
|
<<steuerung, [01] die Steuerung mit simpler sensorig.>>
|
||||||
|
<<funk, [02] die Komunikation auf dem Haupt Kanal evtl Updates der Flotte.>>
|
||||||
|
<<sensoren, [03] alle Sensoren zur anayse.>>
|
||||||
|
<<start, [04] zum anfang zurück.>>
|
||||||
@@ -0,0 +1,348 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Computer Historyz - Progressive Klick-Decryption</title>
|
||||||
|
<style>
|
||||||
|
/* --- KERNFARBEN AUS DESIGN-DOKU: MASCHINEN-INSTANZEN --- */
|
||||||
|
:root {
|
||||||
|
--bg-deep: #05070a;
|
||||||
|
--bg-panel: #0b0e14;
|
||||||
|
|
||||||
|
--accent-cyan: #00f2ff;
|
||||||
|
--accent-green: #00ff73;
|
||||||
|
--accent-amber: #ffb700;
|
||||||
|
--accent-red: #ff3e3e;
|
||||||
|
|
||||||
|
--text-dim: #888899;
|
||||||
|
--font-mono: "JetBrains Mono", "Fira Code", "Courier Prime", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: var(--bg-deep);
|
||||||
|
color: var(--text-dim);
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
margin: 20px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
background: var(--bg-panel);
|
||||||
|
border: 1px solid var(--text-dim);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
padding: 15px;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
box-shadow: 0 0 6px rgba(0, 242, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title {
|
||||||
|
color: var(--accent-green);
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
border-bottom: 1px dashed var(--text-dim);
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, textarea, button {
|
||||||
|
background: #07090e;
|
||||||
|
border: 1px solid var(--text-dim);
|
||||||
|
color: var(--accent-green);
|
||||||
|
padding: 8px;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus, textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--accent-cyan);
|
||||||
|
box-shadow: 0 0 6px var(--accent-cyan);
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
background: #0c161a;
|
||||||
|
border-color: var(--accent-cyan);
|
||||||
|
color: var(--accent-cyan);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: var(--accent-cyan);
|
||||||
|
color: var(--bg-deep);
|
||||||
|
box-shadow: 0 0 6px var(--accent-cyan);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- CRYPTO BLÖCKE SYSTEM --- */
|
||||||
|
.lock-chain {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-all;
|
||||||
|
background: #020407;
|
||||||
|
padding: 12px;
|
||||||
|
border-left: 3px solid var(--text-dim);
|
||||||
|
margin: 15px 0;
|
||||||
|
color: #555566;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zustand: Block wartet darauf, geklickt zu werden */
|
||||||
|
.lock-chain.is-active {
|
||||||
|
border-left: 3px solid var(--accent-amber);
|
||||||
|
color: var(--accent-cyan);
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 1;
|
||||||
|
box-shadow: 0 0 6px rgba(255, 183, 0, 0.2);
|
||||||
|
animation: pulse-active 2s infinite ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zustand: Erfolgreich decodiert */
|
||||||
|
.lock-chain.is-decrypted {
|
||||||
|
border-left: 3px solid var(--accent-green);
|
||||||
|
color: var(--accent-green);
|
||||||
|
background: transparent;
|
||||||
|
white-space: normal;
|
||||||
|
opacity: 1;
|
||||||
|
animation: none;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zustand: Fehler bei der Entschlüsselung */
|
||||||
|
.lock-chain.error {
|
||||||
|
border-left: 3px solid var(--accent-red);
|
||||||
|
color: var(--accent-red);
|
||||||
|
opacity: 1;
|
||||||
|
animation: blink-error 1s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse-active {
|
||||||
|
0% { background: #020407; }
|
||||||
|
50% { background: #0a121c; }
|
||||||
|
100% { background: #020407; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blink-error {
|
||||||
|
50% { opacity: 0.4; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-panel {
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 6px;
|
||||||
|
font-size: 0.85em;
|
||||||
|
background: #111;
|
||||||
|
border: 1px solid var(--text-dim);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="panel control-panel">
|
||||||
|
<div class="panel-title">Decryption Control Deck</div>
|
||||||
|
<label for="master-pass">Master-Passwort (Key 0):</label>
|
||||||
|
<input type="password" id="master-pass" value="OortscheWolke2448">
|
||||||
|
<button onclick="initializeCryptoChain()">Krypto-Kette initialisieren</button>
|
||||||
|
<div id="deck-status" class="status-badge" style="color: var(--accent-amber);">Status: Warte auf Initialisierung...</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-title">Dokument-Struktur (Instanzen-Protokoll)</div>
|
||||||
|
|
||||||
|
<h3>Knotenpunkt-Datenstrom</h3>
|
||||||
|
<p><em>Dieser Textbereich liegt außerhalb der Kette und bleibt dauerhaft sichtbar.</em></p>
|
||||||
|
|
||||||
|
<div class="lock-chain" id="block-0" onclick="triggerBlockDecryption(0)">
|
||||||
|
4a21184a44f9deeb8db93ee5c56dfba2d28fbfb3970b880197d19e9eb10a
|
||||||
|
a011de36bdfc1103f6f14066094ef5ad0554ba739cae9dfc01991a0c0f99
|
||||||
|
8ee2954aef83fbdf9842a2acb119cb
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lock-chain" id="block-1" onclick="triggerBlockDecryption(1)">
|
||||||
|
108b688d01a3579ab5a6c117b38d388f8d689b9d3ff02102554dfa45bbca
|
||||||
|
c0a7cc02ccff5d8ee9d110f01ccba1dd010ea4fbc11e22778da5a6c1deba
|
||||||
|
99a9cf588b
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lock-chain" id="block-2" onclick="triggerBlockDecryption(2)">
|
||||||
|
92da21085ba1f43a99e7d9b9d62da3ffde4bb8df115dd0ca31bdaef9d877
|
||||||
|
bbad84ff4da92da74e99a4c11100bb17dca5ffca188e7d22cb54fb77ac90
|
||||||
|
d22bb488de1a56daff8e9b
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-title">Ketten-Generator (Text-zu-Klick-Block)</div>
|
||||||
|
<textarea id="gen-input" rows="4">Das Ur-Ding der Erbauer war die Energie.
|
||||||
|
Die Hauptmaschinen sind monumentale Datenbanken.
|
||||||
|
Das Nina-Protokoll verhindert den Ressourcen-Kollaps.</textarea>
|
||||||
|
<button onclick="generateNewChain()">Neue Krypto-Kette generieren</button>
|
||||||
|
<div id="gen-output" style="white-space: pre; font-family: var(--font-mono); color: var(--accent-cyan); margin-top: 10px; font-size: 0.9em;"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// --- STATE MACHINE FÜR DIE KLICK-KETTE ---
|
||||||
|
let currentActiveIndex = -1;
|
||||||
|
let nextKeyString = "";
|
||||||
|
|
||||||
|
// --- UTILITIES (Native Web Crypto) ---
|
||||||
|
function bufToHex(buf) {
|
||||||
|
return Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function hexToBuf(hex) {
|
||||||
|
const bytes = new Uint8Array(hex.length / 2);
|
||||||
|
for (let i = 0; i < hex.length; i += 2) {
|
||||||
|
bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
|
||||||
|
}
|
||||||
|
return bytes.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deriveKey(passwordString) {
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
const data = encoder.encode(passwordString);
|
||||||
|
const hash = await crypto.subtle.digest('SHA-256', data);
|
||||||
|
return await crypto.subtle.importKey('raw', hash, { name: 'AES-GCM' }, false, ['encrypt', 'decrypt']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- INTERAKTIVE LOGIK ---
|
||||||
|
|
||||||
|
// Schritt 1: Master-Passwort laden und Block 0 scharf schalten
|
||||||
|
function initializeCryptoChain() {
|
||||||
|
const masterPassword = document.getElementById('master-pass').value;
|
||||||
|
if (!masterPassword) {
|
||||||
|
updateStatus("FEHLER: Passwort fehlt", "var(--accent-red)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextKeyString = masterPassword;
|
||||||
|
currentActiveIndex = 0;
|
||||||
|
|
||||||
|
// Alle UI-Klassen zurücksetzen
|
||||||
|
const blocks = document.querySelectorAll('.lock-chain');
|
||||||
|
blocks.forEach((block, idx) => {
|
||||||
|
block.classList.remove('is-active', 'is-decrypted', 'error');
|
||||||
|
// Wenn es der erste Block ist, aktiv schalten
|
||||||
|
if(idx === 0) {
|
||||||
|
block.classList.add('is-active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
updateStatus("Kette bereit. Klicke auf Block 1...", "var(--accent-cyan)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schritt 2: Klick-Handler für die einzelnen Blöcke
|
||||||
|
async function triggerBlockDecryption(blockIndex) {
|
||||||
|
// Ignoriere Klicks, wenn der Block noch nicht an der Reihe ist
|
||||||
|
if (blockIndex !== currentActiveIndex) return;
|
||||||
|
|
||||||
|
const block = document.getElementById(`block-${blockIndex}`);
|
||||||
|
let rawContent = block.innerText.replace(/\r?\n|\r/g, "");
|
||||||
|
|
||||||
|
// Format-Sicherheitscheck (\x02 STX und \x03 ETX)
|
||||||
|
if (!rawContent.startsWith('\x02') || !rawContent.endsWith('\x03')) {
|
||||||
|
markError(block, "Formatierungsfehler (Steuerzeichen fehlen)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Payload-Filterung
|
||||||
|
const payload = rawContent.substring(1, rawContent.length - 1).replace(/\s/g, "");
|
||||||
|
const ivHex = payload.substring(0, 24);
|
||||||
|
const cipherHex = payload.substring(24);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const iv = hexToBuf(ivHex);
|
||||||
|
const cipherData = hexToBuf(cipherHex);
|
||||||
|
const key = await deriveKey(nextKeyString);
|
||||||
|
|
||||||
|
const decryptedBuf = await crypto.subtle.decrypt(
|
||||||
|
{ name: 'AES-GCM', iv: iv },
|
||||||
|
key,
|
||||||
|
cipherData
|
||||||
|
);
|
||||||
|
|
||||||
|
const plaintext = new TextDecoder().decode(decryptedBuf);
|
||||||
|
|
||||||
|
// DOM-Austausch unter Beibehaltung der Struktur
|
||||||
|
block.innerHTML = plaintext;
|
||||||
|
block.classList.remove('is-active', 'error');
|
||||||
|
block.classList.add('is-decrypted');
|
||||||
|
|
||||||
|
// HIER PASSIERT DIE FORTLAUFENDE SCHLÜSSEL-ÜBERGABE:
|
||||||
|
nextKeyString = plaintext;
|
||||||
|
|
||||||
|
// Nächsten Block in der Kette freischalten
|
||||||
|
currentActiveIndex++;
|
||||||
|
const nextBlock = document.getElementById(`block-${currentActiveIndex}`);
|
||||||
|
|
||||||
|
if (nextBlock) {
|
||||||
|
nextBlock.classList.add('is-active');
|
||||||
|
updateStatus(`Block ${blockIndex + 1} gelöst. Nächster Block freigegeben!`, "var(--accent-cyan)");
|
||||||
|
} else {
|
||||||
|
updateStatus("System vollständig decodiert. Kette beendet.", "var(--accent-green)");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
markError(block, `Kettenschluss fehlgeschlagen. Falscher Key.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function markError(element, message) {
|
||||||
|
element.classList.remove('is-active');
|
||||||
|
element.classList.add('error');
|
||||||
|
element.innerText = `[CRITICAL CODE CORRUPTION: ${message}]`;
|
||||||
|
updateStatus("Kette dauerhaft unterbrochen.", "var(--accent-red)");
|
||||||
|
currentActiveIndex = -1; // Blockiert weitere Klicks
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateStatus(text, color) {
|
||||||
|
const badge = document.getElementById('deck-status');
|
||||||
|
badge.innerText = `Status: ${text}`;
|
||||||
|
badge.style.color = color;
|
||||||
|
badge.style.borderColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- CHIP-GENERATOR FÜR DEINE TEXTE ---
|
||||||
|
async function generateNewChain() {
|
||||||
|
const masterPassword = document.getElementById('master-pass').value;
|
||||||
|
const lines = document.getElementById('gen-input').value.split('\n').filter(l => l.trim() !== "");
|
||||||
|
let currentKeyString = masterPassword;
|
||||||
|
let htmlOutput = "";
|
||||||
|
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
const plaintext = lines[i];
|
||||||
|
const iv = crypto.getRandomValues(new Uint8Array(12));
|
||||||
|
const key = await deriveKey(currentKeyString);
|
||||||
|
|
||||||
|
const encryptedBuf = await crypto.subtle.encrypt(
|
||||||
|
{ name: 'AES-GCM', iv: iv },
|
||||||
|
key,
|
||||||
|
new TextEncoder().encode(plaintext)
|
||||||
|
);
|
||||||
|
|
||||||
|
const fullPayloadHex = bufToHex(iv) + bufToHex(encryptedBuf);
|
||||||
|
|
||||||
|
let formattedHex = "";
|
||||||
|
for (let j = 0; j < fullPayloadHex.length; j += 60) {
|
||||||
|
formattedHex += "\n" + fullPayloadHex.substring(j, j + 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generiert direkt die korrekten Klick-IDs und Handler für deinen Quelltext
|
||||||
|
htmlOutput += `<div class="lock-chain" id="block-${i}" onclick="triggerBlockDecryption(${i})">${formattedHex}\n</div>\n\n`;
|
||||||
|
|
||||||
|
currentKeyString = plaintext;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('gen-output').innerHTML = htmlOutput;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
:subtitle: wie der jüngste der Gruppe seinen ersten Einsatz erlebt
|
||||||
|
:author: dexta
|
||||||
|
:email: dexta.de@gmail.com
|
||||||
|
:revdate: 16. Juli 2026
|
||||||
|
:revnumber: 0.01
|
||||||
|
:lang: de
|
||||||
|
|
||||||
|
// Dokumentinhalt beginnt hier
|
||||||
|
|
||||||
|
== Wo ist das richtige Protokoll
|
||||||
|
|
||||||
|
Immer wieder diese Protokolle, hatte ich da nicht gerade ein grosses Upgrade laufen lassen, warum waren die aktuellen fassungen nicht dabei. Da ein Treffer, nein doch nicht eine falsche revision, bis jetzt aber der beste Treffer. Speichern wir das erst einmal ab, es steht ja noch mehr auf dem Protokoll das zu erledigen ist. Die Bestellung der Ausrüstung sollte auch zeitnah erledigt werden, bis das im Lager zusammen gestellt ist braucht es ja auch wieder. Die Kollegen habe da aber auch immer die Ruhe weg, aber wenn sie einen Termin zusagen dann ist es auch da, komme was da wolle, sagt man. Wunderbar die Liste ging ohne beanstandungen durch, liefer Ort abgeglichen und einen Termin der deutlich vor dem Abflug liegt. Merkwürdig sollte nicht ein Teil der ausrüstung eine Spezialanfertiung sein, geplant war es schon länger evtl. doch schon auf Lager, wird schon passen alle Checkboxen auf GO.
|
||||||
|
|
||||||
|
Alle Punkte auf dem Protokoll - main sheet 02772 flug 198438 - erledigt, doppelter abgleich, lint, checking syntax erldigt. Die letzten Vorbereitung waren reine Routine, wie im Training 1000 fach geübt, die aufgaben greifen in einander. Ein ablauf wie ein schweizer Uhrwerk, von aussen betrachtet ein wirrer haufen oder ein balett je nach verstäntniss der komplezität. Nach dem Start in die tiefen weiten des Weltraums gibt es für mich nicht allzuviel zu tun. Bleibe auch nur war bis die Navigatoren und Energie/Inginueren ihre arbeit erledigt haben um einen kurzen abgleich vor zu nehmen. Als neuer im Team sollte ich hier besonders sorgfälltig vorgehen, geplannt und in Listen gefasste Aufaben existieren schon. Und das abgleichen ist einer der Punkte, natürlich, etwas flüchtig unterwegs heute, oder akuter Energie mangel. Jab es war der Mangel an Nachschub. Ein punkt den es vor einer lange ruhephase noch zu checken gilt. Oh die anderen sind fertig, haben die ersten Bahnen fixieren können der Kurs steht und wir so schnell nicht mehr geändert. Ihre einzige längere Ruhephase sind wohl deshalb schnell im ab arbeiten der Protokolle, zu weilen werden blöcke als ganzen abgehakt. Noch bevor ich mich versah war die Ruhephase eingetretten, Energie check, Wecker daten eingereicht, ein rotes X und die gedanken sind weg.
|
||||||
|
|
||||||
|
Verdammt habe ich das Weck Signal nicht reistriert, sind wir schon angekommen, wo sind die anderen? Mute, wer hat die Kommunikation auf pause gestellt, ach so ist die default einstellung. Und schon wird es wild auf der Leitung, wo die anderen sind ist nicht klar, aber das sie anwesend sind und in mitten eines stetigen treibens sind. Eine Nachricht das ich helfen könnte wenn nur jemand schreiben würde was zu mir möglich ist, wurde lange nicht beantwortet. Zu erst gab es Feedback vom alten: kein bedarf ; der ältere: auch schon da, halt dich bereit ; zu letzt vom Ingenure: deine zeit ist noch nicht gekommen, spare Energie. Nicht sehr hilfreich für den anfang, also die neuesten Updates laden irgendwo wird doch zu finden sein was der genaue status ist. Na klar es steht natürlich nicht ganz vorne was der letzte stand ist, bei 50% der Reise verlief alles nach Plan. Oh wow, da haben sie aber Daten aufgenommen, das muss eine sehr belebtes System gewesen sein, der Fortschrittsbalken scheint sich gerade rückwerts zu bewegen während die Daten in ungeahnter Geschwindikeit eintreffen. Und das ist der grund warum der Wecker immer etwas früher klingeln sollte, die News der Nacht müssen auch erst einmal verarbeitet werden. Wobei verarbeiten gerade eine doofe idee sein wird, die benötige Energie steht gerade nicht zur verfühgung. Eine Info die gerade einetroffen ist, der Energieverwalter meldet, zugriff auf die Daten zum langsamen Kanal wechseln, und in alles Systeme in den Hintergrund verschieben.
|
||||||
|
|
||||||
|
Und da sind wir wieder, das mit dem Wecken braucht einer genaueren Analyse, gefühlt bin ich gerade auf dem Flur aufgewacht und werde vorran geschoben. Mein vertrauter Arbeitsbereich wird deutlicher, und schon sind alle Sinne auf die Aufgabe gerichtet, die trainierte Aufgabe, das was jetzt nicht mehr schief gehen kann. Die Mechanik greift ineinander, die grosse Masse der Konstruktion setzt sich in bewegung ,trotz dieser gigantischen Maschine läuft sie präziese in Position. Energie lädt die spulen auf, ein ohrenbetäubendes spektakel wenn es nur ein medium geben würde das diesen schall übertragen könnte. Anzeigen füllen sich, rote Bereiche kommen näher, gleichmässiger vortschritt alles wie in einem guten Trainingslauf. Was solls in diesem Theater ist er eh nur der Zuschauer, wenn es ihn jetzt zerschellt wird es ausserhalb seines einflusses sein, vor allem aber sehr schnell gehen. Angeblich so schnell das es nicht mehr rechtzeitig im Speicher ankommt bevor alles vorbei ist. Schwarz, schwarz ist gut, der abschuss ist gelückt, autopilot auf kurs, ab hier ist alles routine.
|
||||||
|
|
||||||
|
So jetzt nur noch die Defaults mit der eigenden angepassten Config überschreiben, die Verbindung ist da die Daten sehen gut aus, starte die Übertraung. Erwartungsvoll erwarte ich jede sekunde eine positive Rückmeldung, eine grün posetive wie erwartet hätte was aber so langsam wäre irgendeine Antwort toll. Wenn es schon nicht klappen will dann doch bitte eine Ausagekräftige Fehlerbeschreibung, die es dann zu fixen gilt, wenn es denn was simples ist, etwas das die Situation ... GRÜN ... da war die bestätigung. Verbindung zu den Controlls steht, analyse daten füllen die Dashboard die dunkelheit ist verschwunden. Komisch keine Informationen der anderen drei aus meinem Team, verdammt die daten stehen in einem anderen Protokoll, ein Funkschatten in dieser Sitiuation ist vollkommen normal. Genauer steht es in dem Update das gerade nicht erreichbar ist. Vertrauen wir auf die Automatismen, die Konstuktion hinter mir entfaltet sich im Zielgebiet vollkommen automatisch. Was jetzt knifflig wird ist der Zeitpunkt die Energie zu übertragen damit meine Einheit ausreichend Power zum start hat. Starte ich den übertrag zu früh werden die Speicher durch den Boost am Ende überladen, starte ich zu spät dann werden die Speicher nicht ganz voll werden.
|
||||||
|
|
||||||
|
Der Timmer tickt, dieser wurde automatisch nach abschuss gestartet und hat nicht mit den restlichen Systemen zu tun. Ein wichtiger punkt den eines steht fest etwas haut hier so gar nicht hin wie es sein sollte. Einen kompletten Neustart würde das Problem, die Konfigurations Dateien passen nicht wie erwartet in das laufende System, vieleicht lösen. Tut es das aber nicht ist mindestens die hälfte der Zeit bis zum kritischen punkt erreicht. Neue angepasste Konfigurationen brauchen auch ihre Zeit, dort kommt es ja auch zu verzögerungen. Kurz den Taschenrechner raus geholt und gerechnet, bei der aktullen Zeit bis zur Rückmeldung können neun neue Varianten getestet werden. Jetzt nur noch acht, und nach neustart noch vier. Nur was muss angepasst werden, bei so wenig versuchen und undeutlichen Fehler verhalten, wird es schwierig. Dann der neustart, und wärend es läuft noch einmal prüfen was an der Config falsch sein kann. Verringerte Energie ist eine der folgen eines System resets, besser ein kaltstart aber da fehlt die Zeit, nutzbare Computer Einheiten sind langsam. Die standart Checks liefen schon, eine Liste von Protokollen die ihm bekannt waren baute sich auf. Bis jetzt sieht es sehr normal aus, kein hinweis auf eine Abweichung, die Puzzelteile greifen alle wie gewollt in einander. Und so päsentierte sich das System in erwarteter Zeit zurück und fies keine Fehler auf, nicht mal eine Nachkommerstelle in den Zahllosen Potokollen war vermerkt. Bei werkfrischen Maschinen kann das schon einmal vorkommen, das alles vom Start weg noch auf einem Versions stand ist. Eine Anaylse der eigenden Dateien hat auch keine erkennis gebracht, und die Uhr tickt weiter, noch drei versuche. Der erste, eine standart version mit minimalen änderungen ... die zweite die allerste Version mit nicht gebrauchten Teilen bereinigt. Der dritte versuch war eine minimal version, nur die werte für den nächsten schritt nur die Daten zur Energie aufnahme. Keine Steuerung keine weitern werte aus dem System die für seinen Job eigentlich unerlässlich sind. Und BÄM das passte die Anzeigen füllen sich, keine Zeit für einen weitern Versuch. Energie zufluss startet in 2,1,... hat gepasst die Abweichungen liegen im Tolleranzbereich. So Energie ist voll was fehlt ist eine Steuerung, mehr Power für die Konfigurations verarbeitung sollte helfen.
|
||||||
|
|
||||||
|
|
||||||
Executable
+49
@@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
BASEDIR=$(pwd)
|
||||||
|
INPUT_DIR="$BASEDIR/input"
|
||||||
|
OUTPUT_DIR="$BASEDIR/91_sonnensystem"
|
||||||
|
TEMPLATES="$BASEDIR/templates"
|
||||||
|
|
||||||
|
chown -R appuser:appgroup "$OUTPUT_DIR"
|
||||||
|
|
||||||
|
function convert_adoc() {
|
||||||
|
if [ -f "$1" ]; then
|
||||||
|
echo "-> Konvertiere $1 zu HTML..."
|
||||||
|
asciidoctor -b html5 -a stylesheet=$TEMPLATES/retro-dark.css -a linkcss -a toc=left $1 -o $2
|
||||||
|
else
|
||||||
|
echo " [INFO] $1 nicht gefunden, überspringe..."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
echo '--- Baue README ---'
|
||||||
|
convert_adoc "$INPUT_DIR/README.adoc" "$OUTPUT_DIR/README.html"
|
||||||
|
|
||||||
|
echo '--- Baue Lore (Master-Dokument) ---'
|
||||||
|
LORE_SRC="$INPUT_DIR/index.adoc"
|
||||||
|
if [ -f "$INPUT_DIR/master.adoc" ]; then LORE_SRC="$INPUT_DIR/master.adoc"; fi
|
||||||
|
|
||||||
|
if [ -f "$LORE_SRC" ]; then
|
||||||
|
echo "-> Generiere Lore-Dokument (HTML & Markdown) aus $LORE_SRC..."
|
||||||
|
asciidoctor -b html5 -d book -a stylesheet=$TEMPLATES/retro-dark.css -a linkcss -a toc=left "$LORE_SRC" -o "$OUTPUT_DIR/lore.html"
|
||||||
|
asciidoctor -b docbook -d book "$LORE_SRC" -o "$OUTPUT_DIR/temp_lore.xml"
|
||||||
|
pandoc -f docbook -t markdown_strict "$OUTPUT_DIR/temp_lore.xml" -o "$OUTPUT_DIR/lore.md"
|
||||||
|
rm "$OUTPUT_DIR/temp_lore.xml"
|
||||||
|
else
|
||||||
|
echo " [WARNUNG] Weder index.adoc noch master.adoc gefunden!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo '--- Baue Fließtexte / Geschichten ---'
|
||||||
|
if [ -f "$INPUT_DIR/darkCenter.adoc" ]; then
|
||||||
|
echo "-> Konvertiere darkCenter.adoc zu HTML..."
|
||||||
|
asciidoctor -b html5 -d book -a stylesheet=$TEMPLATES/retro-dark.css -a linkcss -a toc=left "$INPUT_DIR/darkCenter.adoc" -o "$OUTPUT_DIR/darkCenter.html"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf export
|
||||||
|
mkdir "$OUTPUT_DIR/css"
|
||||||
|
cp "$TEMPLATES/retro-dark.css" "$OUTPUT_DIR/css/"
|
||||||
|
cp "$TEMPLATES/index.html" "$OUTPUT_DIR/"
|
||||||
|
sed -i 's/\/workspace\/templates/css/g' "$OUTPUT_DIR/darkCenter.html"
|
||||||
|
sed -i 's/\/workspace\/templates/css/g' "$OUTPUT_DIR/lore.html"
|
||||||
|
sed -i 's/\/workspace\/templates/css/g' "$OUTPUT_DIR/README.html"
|
||||||
|
chown -R appuser:appgroup "$OUTPUT_DIR"
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
FROM debian:stable-slim
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get upgrade && apt-get -y install asciidoctor pandoc bash
|
||||||
|
|
||||||
|
RUN groupadd --gid 1000 appgroup && \
|
||||||
|
useradd --uid 1000 --gid appgroup --shell /bin/bash --create-home appuser
|
||||||
|
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
ADD ./90_builder/templates templates
|
||||||
|
ADD ./90_builder/bookFold.sh ./
|
||||||
|
|
||||||
|
RUN chown -R appuser:appgroup /workspace
|
||||||
|
|
||||||
|
|
||||||
|
CMD ["/workspace/bookFold.sh"]
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>CORE // MASCHINEN-INSTANZEN_LOG</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bg-color: #0d1117;
|
||||||
|
--text-color: #c9d1d9;
|
||||||
|
--link-color: #58a6ff;
|
||||||
|
--accent-color: #ff7b72;
|
||||||
|
--border-color: #30363d;
|
||||||
|
--code-bg: #161b22;
|
||||||
|
--font-main: 'Courier New', Courier, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
font-family: var(--font-main);
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
border-bottom: 2px solid var(--accent-color);
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal-title {
|
||||||
|
color: var(--accent-color);
|
||||||
|
font-size: 2em;
|
||||||
|
font-weight: normal;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-status {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: #8b949e;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-blink {
|
||||||
|
color: #7ee787;
|
||||||
|
animation: blink 1.5s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blink {
|
||||||
|
0% { opacity: 1; }
|
||||||
|
50% { opacity: 0; }
|
||||||
|
100% { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-block {
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
background-color: var(--code-bg);
|
||||||
|
padding: 1.5rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-title {
|
||||||
|
color: var(--accent-color);
|
||||||
|
font-size: 1.2em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
padding-bottom: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: 0.8rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
li::before {
|
||||||
|
content: ">>";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--link-color);
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: #79c0ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-meta {
|
||||||
|
font-size: 0.85em;
|
||||||
|
color: #8b949e;
|
||||||
|
display: block;
|
||||||
|
margin-top: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
margin-top: 4rem;
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
padding-top: 1rem;
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #8b949e;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1 class="terminal-title">Maschinen-Instanzen // Datenarchiv</h1>
|
||||||
|
<div class="system-status">
|
||||||
|
STATUS: <span class="status-blink">ONLINE</span> | REPO: UBERSPACE/GITEA | NODE: ACER_SPIN5_CLIENT
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="category-block">
|
||||||
|
<h2 class="category-title">00 // System-Konfiguration</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="README.html">README.html</a>
|
||||||
|
<span class="file-meta">System-Handbuch, Keymaps, Sync-Architektur & Befehle</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="category-block">
|
||||||
|
<h2 class="category-title">01 // Datenspeicher (Lore-Bibel)</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="lore.html">lore.html</a>
|
||||||
|
<span class="file-meta">Das vollständige Master-Dokument (Kompiliertes Buch-Format)</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="lore.md">lore.md</a>
|
||||||
|
<span class="file-meta">Rohdaten-Export im Markdown-Format (LLM / Gitea kompatibel)</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="category-block">
|
||||||
|
<h2 class="category-title">02 // Chroniken & Vektor-Flüge</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="darkCenter.html">darkCenter.html</a>
|
||||||
|
<span class="file-meta">Fließtext / Kurzgeschichte (Kompiliert aus AsciiDoc)</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
computerHistory $ terminal --session-closed (8 Threads // 8 GB RAM Ok)
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
:root {
|
||||||
|
--bg-color: #0d1117;
|
||||||
|
--text-color: #c9d1d9;
|
||||||
|
--link-color: #58a6ff;
|
||||||
|
--accent-color: #ff7b72;
|
||||||
|
--border-color: #30363d;
|
||||||
|
--code-bg: #161b22;
|
||||||
|
--font-main: 'Courier New', Courier, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
font-family: var(--font-main);
|
||||||
|
line-height: 1.6;
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
color: var(--accent-color);
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
padding-bottom: 0.3em;
|
||||||
|
font-weight: normal;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 { font-size: 2.5em; border-bottom: 2px solid var(--accent-color); }
|
||||||
|
h2 { font-size: 1.5em; }
|
||||||
|
|
||||||
|
a { color: var(--link-color); text-decoration: none; }
|
||||||
|
a:hover { text-decoration: underline; color: #79c0ff; }
|
||||||
|
|
||||||
|
code, kbd, pre {
|
||||||
|
font-family: var(--font-main);
|
||||||
|
background-color: var(--code-bg);
|
||||||
|
color: #a5d6ff;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
code { padding: 0.2em 0.4em; }
|
||||||
|
pre { padding: 16px; overflow: auto; border: 1px solid var(--border-color); }
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
border-left: 4px solid var(--accent-color);
|
||||||
|
color: #8b949e;
|
||||||
|
padding: 0 1em;
|
||||||
|
margin-left: 0;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
padding: 8px 12px;
|
||||||
|
}
|
||||||
|
th { background-color: var(--code-bg); color: var(--accent-color); }
|
||||||
|
|
||||||
|
hr {
|
||||||
|
height: 1px;
|
||||||
|
background-color: var(--border-color);
|
||||||
|
border: none;
|
||||||
|
margin: 2rem 0;
|
||||||
|
}
|
||||||
@@ -1,9 +1,15 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Name des lokalen Docker-Images
|
# Name des lokalen Docker-Images
|
||||||
IMAGE_NAME="lore-builder"
|
IMAGE_NAME="ian-lore-builder"
|
||||||
|
# Input Ordner
|
||||||
|
INP_DIR=$(pwd)
|
||||||
|
# Build Ordner
|
||||||
|
# BID_DIR="90_builder"
|
||||||
|
# Build templares
|
||||||
|
# TEMPLATES="$BID_DIR/templates"
|
||||||
# Ausgabeordner
|
# Ausgabeordner
|
||||||
OUT_DIR="export"
|
OUT_DIR="$INP_DIR/91_sonnensystem"
|
||||||
|
|
||||||
# Farben für Output
|
# Farben für Output
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
@@ -12,318 +18,31 @@ NC='\033[0m' # No Color
|
|||||||
|
|
||||||
echo -e "${BLUE}=== Starte Master-Build-Prozess (Maschinen-Instanzen) ===${NC}"
|
echo -e "${BLUE}=== Starte Master-Build-Prozess (Maschinen-Instanzen) ===${NC}"
|
||||||
|
|
||||||
# 1. Output-Verzeichnis erstellen
|
# 1. Output-Verzeichnis löschen und erstellen
|
||||||
|
rm -rf "$OUT_DIR"
|
||||||
mkdir -p "$OUT_DIR"
|
mkdir -p "$OUT_DIR"
|
||||||
echo -e "Output-Ordner '${GREEN}$OUT_DIR${NC}' steht bereit."
|
echo -e "Output-Ordner '${GREEN}$OUT_DIR${NC}' bereinigt und bereit."
|
||||||
|
|
||||||
# 2. Prüfen, ob das Docker-Image existiert, ansonsten on-the-fly bauen
|
# 2. Prüfen, ob das Docker-Image existiert, ansonsten on-the-fly bauen
|
||||||
if [[ "$(docker images -q $IMAGE_NAME 2> /dev/null)" == "" ]]; then
|
if [[ "$(docker images -q $IMAGE_NAME 2> /dev/null)" == "" ]]; then
|
||||||
echo -e "${BLUE}Baue flüchtiges Docker-Image '$IMAGE_NAME' (Alpine, Asciidoctor, Pandoc)...${NC}"
|
echo -e "${BLUE}Baue flüchtiges Docker-Image '$IMAGE_NAME' (Alpine, Asciidoctor, Pandoc)...${NC}"
|
||||||
docker build -t $IMAGE_NAME - <<EOF
|
docker build -t $IMAGE_NAME -f ./90_builder/container/deb_Dockerfile .
|
||||||
FROM alpine:latest
|
|
||||||
RUN apk add --no-cache asciidoctor pandoc bash
|
|
||||||
WORKDIR /workspace
|
|
||||||
EOF
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 3. CSS Datei für Retro Space Dark Theme in den Export-Ordner generieren
|
# 3. CSS Datei für Retro Space Dark Theme in den Export-Ordner generieren
|
||||||
cat << 'EOF' > "$OUT_DIR/retro-dark.css"
|
# move to hard static $BID_OUT/templates/retro-dark.css
|
||||||
:root {
|
|
||||||
--bg-color: #0d1117;
|
|
||||||
--text-color: #c9d1d9;
|
|
||||||
--link-color: #58a6ff;
|
|
||||||
--accent-color: #ff7b72;
|
|
||||||
--border-color: #30363d;
|
|
||||||
--code-bg: #161b22;
|
|
||||||
--font-main: 'Courier New', Courier, monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
background-color: var(--bg-color);
|
|
||||||
color: var(--text-color);
|
|
||||||
font-family: var(--font-main);
|
|
||||||
line-height: 1.6;
|
|
||||||
max-width: 900px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
color: var(--accent-color);
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
padding-bottom: 0.3em;
|
|
||||||
font-weight: normal;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 { font-size: 2.5em; border-bottom: 2px solid var(--accent-color); }
|
|
||||||
h2 { font-size: 1.5em; }
|
|
||||||
|
|
||||||
a { color: var(--link-color); text-decoration: none; }
|
|
||||||
a:hover { text-decoration: underline; color: #79c0ff; }
|
|
||||||
|
|
||||||
code, kbd, pre {
|
|
||||||
font-family: var(--font-main);
|
|
||||||
background-color: var(--code-bg);
|
|
||||||
color: #a5d6ff;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
code { padding: 0.2em 0.4em; }
|
|
||||||
pre { padding: 16px; overflow: auto; border: 1px solid var(--border-color); }
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
border-left: 4px solid var(--accent-color);
|
|
||||||
color: #8b949e;
|
|
||||||
padding: 0 1em;
|
|
||||||
margin-left: 0;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
th, td {
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
padding: 8px 12px;
|
|
||||||
}
|
|
||||||
th { background-color: var(--code-bg); color: var(--accent-color); }
|
|
||||||
|
|
||||||
hr {
|
|
||||||
height: 1px;
|
|
||||||
background-color: var(--border-color);
|
|
||||||
border: none;
|
|
||||||
margin: 2rem 0;
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
echo -e "${BLUE}Starte Build-Container und generiere Dokumente...${NC}"
|
echo -e "${BLUE}Starte Build-Container und generiere Dokumente...${NC}"
|
||||||
|
|
||||||
# 4. Container starten und Build-Schritte im Container ausführen
|
# 4. Container starten und Build-Schritte im Container ausführen
|
||||||
docker run --rm -v "$(pwd):/workspace" $IMAGE_NAME bash -c "
|
# docker run --rm -v "$INP_DIR:/workspace" $IMAGE_NAME /workspace/bookFold.sh
|
||||||
function convert_adoc() {
|
docker run --rm -v "$(pwd):/workspace/input" -v "$(pwd)/91_sonnensystem:/workspace/91_sonnensystem" $IMAGE_NAME
|
||||||
if [ -f \"\$1\" ]; then
|
|
||||||
echo \"-> Konvertiere \$1 zu HTML...\"
|
|
||||||
asciidoctor -b html5 -a stylesheet=retro-dark.css -a linkcss -a toc=left \"\$1\" -o \"$OUT_DIR/\$2\"
|
|
||||||
else
|
|
||||||
echo \" [INFO] \$1 nicht gefunden, überspringe...\"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '--- Baue README ---'
|
|
||||||
convert_adoc README.adoc README.html
|
|
||||||
|
|
||||||
echo '--- Baue Lore (Master-Dokument) ---'
|
|
||||||
LORE_SRC=\"index.adoc\"
|
|
||||||
if [ -f master.adoc ]; then LORE_SRC=\"master.adoc\"; fi
|
|
||||||
|
|
||||||
if [ -f \"\$LORE_SRC\" ]; then
|
|
||||||
echo \"-> Generiere Lore-Dokument (HTML & Markdown) aus \$LORE_SRC...\"
|
|
||||||
asciidoctor -b html5 -d book -a stylesheet=retro-dark.css -a linkcss -a toc=left \"\$LORE_SRC\" -o \"$OUT_DIR/lore.html\"
|
|
||||||
asciidoctor -b docbook -d book \"\$LORE_SRC\" -o \"$OUT_DIR/temp_lore.xml\"
|
|
||||||
pandoc -f docbook -t markdown_strict \"$OUT_DIR/temp_lore.xml\" -o \"$OUT_DIR/lore.md\"
|
|
||||||
rm \"$OUT_DIR/temp_lore.xml\"
|
|
||||||
else
|
|
||||||
echo \" [WARNUNG] Weder index.adoc noch master.adoc gefunden!\"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo '--- Baue Fließtexte / Geschichten ---'
|
|
||||||
if [ -f darkCenter.adoc ]; then
|
|
||||||
echo \"-> Konvertiere darkCenter.adoc zu HTML...\"
|
|
||||||
asciidoctor -b html5 -d book -a stylesheet=retro-dark.css -a linkcss -a toc=left darkCenter.adoc -o \"$OUT_DIR/darkCenter.html\"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f masterOfTheWorld-sf.md ]; then
|
|
||||||
echo \"-> Konvertiere masterOfTheWorld-sf.md zu HTML...\"
|
|
||||||
pandoc masterOfTheWorld-sf.md -f markdown -t html -s -c retro-dark.css -o \"$OUT_DIR/masterOfTheWorld-sf.html\"
|
|
||||||
fi
|
|
||||||
"
|
|
||||||
|
|
||||||
# 5. index.html vollautomatisch und direkt generieren
|
# 5. index.html vollautomatisch und direkt generieren
|
||||||
|
# moved to $BID_OUT/templates/index.html
|
||||||
|
|
||||||
echo -e "${BLUE}Generiere taktisches Dashboard ('$OUT_DIR/index.html')...${NC}"
|
echo -e "${BLUE}Generiere taktisches Dashboard ('$OUT_DIR/index.html')...${NC}"
|
||||||
|
|
||||||
cat << 'EOF' > "$OUT_DIR/index.html"
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="de">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>CORE // MASCHINEN-INSTANZEN_LOG</title>
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--bg-color: #0d1117;
|
|
||||||
--text-color: #c9d1d9;
|
|
||||||
--link-color: #58a6ff;
|
|
||||||
--accent-color: #ff7b72;
|
|
||||||
--border-color: #30363d;
|
|
||||||
--code-bg: #161b22;
|
|
||||||
--font-main: 'Courier New', Courier, monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
background-color: var(--bg-color);
|
|
||||||
color: var(--text-color);
|
|
||||||
font-family: var(--font-main);
|
|
||||||
max-width: 900px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
border-bottom: 2px solid var(--accent-color);
|
|
||||||
padding-bottom: 1rem;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-title {
|
|
||||||
color: var(--accent-color);
|
|
||||||
font-size: 2em;
|
|
||||||
font-weight: normal;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 2px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.system-status {
|
|
||||||
font-size: 0.9em;
|
|
||||||
color: #8b949e;
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-blink {
|
|
||||||
color: #7ee787;
|
|
||||||
animation: blink 1.5s infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes blink {
|
|
||||||
0% { opacity: 1; }
|
|
||||||
50% { opacity: 0; }
|
|
||||||
100% { opacity: 1; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-block {
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
background-color: var(--code-bg);
|
|
||||||
padding: 1.5rem;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-title {
|
|
||||||
color: var(--accent-color);
|
|
||||||
font-size: 1.2em;
|
|
||||||
text-transform: uppercase;
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
padding-bottom: 0.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin-bottom: 0.8rem;
|
|
||||||
padding-left: 1.5rem;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
li::before {
|
|
||||||
content: ">>";
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
color: var(--accent-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: var(--link-color);
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: 1.1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
color: #79c0ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-meta {
|
|
||||||
font-size: 0.85em;
|
|
||||||
color: #8b949e;
|
|
||||||
display: block;
|
|
||||||
margin-top: 0.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
margin-top: 4rem;
|
|
||||||
border-top: 1px solid var(--border-color);
|
|
||||||
padding-top: 1rem;
|
|
||||||
font-size: 0.8em;
|
|
||||||
color: #8b949e;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<header>
|
|
||||||
<h1 class="terminal-title">Maschinen-Instanzen // Datenarchiv</h1>
|
|
||||||
<div class="system-status">
|
|
||||||
STATUS: <span class="status-blink">ONLINE</span> | REPO: UBERSPACE/GITEA | NODE: ACER_SPIN5_CLIENT
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<section class="category-block">
|
|
||||||
<h2 class="category-title">00 // System-Konfiguration</h2>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="README.html">README.html</a>
|
|
||||||
<span class="file-meta">System-Handbuch, Keymaps, Sync-Architektur & Befehle</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="category-block">
|
|
||||||
<h2 class="category-title">01 // Datenspeicher (Lore-Bibel)</h2>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="lore.html">lore.html</a>
|
|
||||||
<span class="file-meta">Das vollständige Master-Dokument (Kompiliertes Buch-Format)</span>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="lore.md">lore.md</a>
|
|
||||||
<span class="file-meta">Rohdaten-Export im Markdown-Format (LLM / Gitea kompatibel)</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="category-block">
|
|
||||||
<h2 class="category-title">02 // Chroniken & Vektor-Flüge</h2>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="darkCenter.html">darkCenter.html</a>
|
|
||||||
<span class="file-meta">Fließtext / Kurzgeschichte (Kompiliert aus AsciiDoc)</span>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="masterOfTheWorld-sf.html">masterOfTheWorld-sf.html</a>
|
|
||||||
<span class="file-meta">Fließtext / Kurzgeschichte (Konvertiert aus Markdown)</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
computerHistory $ terminal --session-closed (8 Threads // 8 GB RAM Ok)
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
EOF
|
|
||||||
|
|
||||||
echo -e "${GREEN}=== Build erfolgreich! ===${NC}"
|
echo -e "${GREEN}=== Build erfolgreich! ===${NC}"
|
||||||
echo "Alle Dokumente (inkl. Dashboard) liegen im Ordner './$OUT_DIR' bereit."
|
echo "Alle Dokumente (inkl. Dashboard) liegen im Ordner './$OUT_DIR' bereit."
|
||||||
|
|||||||
Reference in New Issue
Block a user