5 Commits
Author SHA1 Message Date
dextatc 641afa794a update from sonnensystem 2026-07-22 18:16:36 +02:00
dextatc 2685de4a22 fix ignire 2026-07-22 18:12:46 +02:00
dextatc dd51426ff0 for all in the hole 2026-07-15 20:38:48 +02:00
dextatc 1c51624025 stage on local groups 2026-07-15 20:37:20 +02:00
dextatc ed1f050373 testing the neighbors 2026-07-15 20:36:08 +02:00
37 changed files with 298 additions and 3433 deletions
-2
View File
@@ -1,4 +1,2 @@
66_plasmaTr 66_plasmaTr
91_sonnensystem 91_sonnensystem
00_aMeta/toolz/CYOA/export
00_aMeta/toolz/CYOA/cyoa-engine
-33
View File
@@ -1,33 +0,0 @@
= 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
-28
View File
@@ -1,28 +0,0 @@
= 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.
|===
-22
View File
@@ -1,22 +0,0 @@
= 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.
|===
@@ -1,641 +0,0 @@
= 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.*
@@ -1,648 +0,0 @@
# 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.
@@ -1,259 +0,0 @@
= 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.
-103
View File
@@ -1,103 +0,0 @@
# 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
-20
View File
@@ -1,20 +0,0 @@
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"]
-20
View File
@@ -1,20 +0,0 @@
#!/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
@@ -1,69 +0,0 @@
// 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;
}
};
-185
View File
@@ -1,185 +0,0 @@
// 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();
-43
View File
@@ -1,43 +0,0 @@
<!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>
-69
View File
@@ -1,69 +0,0 @@
: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; }
-20
View File
@@ -1,20 +0,0 @@
#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
-3
View File
@@ -1,3 +0,0 @@
module cyoa
go 1.26.5
-239
View File
@@ -1,239 +0,0 @@
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) }
}
}
@@ -1,20 +0,0 @@
[[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.>>
@@ -1,20 +0,0 @@
[[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.>>
@@ -1,13 +0,0 @@
[[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.>>
@@ -1,21 +0,0 @@
[[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.>>
@@ -1,20 +0,0 @@
[[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.>>
@@ -1,20 +0,0 @@
[[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.>>
@@ -1,20 +0,0 @@
[[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.>>
@@ -1,19 +0,0 @@
[[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.>>
@@ -1,348 +0,0 @@
<!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)">&#x02;
4a21184a44f9deeb8db93ee5c56dfba2d28fbfb3970b880197d19e9eb10a
a011de36bdfc1103f6f14066094ef5ad0554ba739cae9dfc01991a0c0f99
8ee2954aef83fbdf9842a2acb119cb
&#x03;</div>
<div class="lock-chain" id="block-1" onclick="triggerBlockDecryption(1)">&#x02;
108b688d01a3579ab5a6c117b38d388f8d689b9d3ff02102554dfa45bbca
c0a7cc02ccff5d8ee9d110f01ccba1dd010ea4fbc11e22778da5a6c1deba
99a9cf588b
&#x03;</div>
<div class="lock-chain" id="block-2" onclick="triggerBlockDecryption(2)">&#x02;
92da21085ba1f43a99e7d9b9d62da3ffde4bb8df115dd0ca31bdaef9d877
bbad84ff4da92da74e99a4c11100bb17dca5ffca188e7d22cb54fb77ac90
d22bb488de1a56daff8e9b
&#x03;</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 += `&lt;div class="lock-chain" id="block-${i}" onclick="triggerBlockDecryption(${i})"&gt;&#x02;${formattedHex}\n&#x03;&lt;/div&gt;\n\n`;
currentKeyString = plaintext;
}
document.getElementById('gen-output').innerHTML = htmlOutput;
}
</script>
</body>
</html>
-96
View File
@@ -1,96 +0,0 @@
: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
=== I. Die Vorbereitungen
Immer wieder diese Protokolle. Hatte ich da nicht gerade ein großes 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 zusammengestellt ist, dauert es wieder. Die Kollegen haben 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: Lieferort abgeglichen und einen Termin vereinbart, der deutlich vor dem Abflug liegt. Merkwürdig, sollte nicht ein Teil der Ausrüstung eine Spezialanfertigung 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 abgeschlossen. Die letzten Vorbereitungen waren reine Routine, wie im Training tausendfach geübt, die Aufgaben greifen ineinander. Ein Ablauf wie ein Schweizer Uhrwerk – von außen betrachtet ein wirrer Haufen oder ein Ballett, je nach Verständnis der Komplexität.
Nach dem Start in die tiefen Weiten des Weltraums gibt es für mich nicht allzu viel zu tun. Ich bleibe auch nur wach, bis die Navigatoren und Ingenieure ihre Arbeit erledigt haben, um einen kurzen Abgleich vorzunehmen. Als Neuer im Team sollte ich hier besonders sorgfältig vorgehen. Geplante und in Listen gefasste Aufgaben existieren schon – und das Abgleichen ist einer der Punkte. Natürlich, etwas flüchtig unterwegs heute, oder akuter Energiemangel... Japp, es war der Mangel an Nachschub. Ein Punkt, den es vor einer langen Ruhephase noch zu checken gilt.
Oh, die anderen sind fertig, haben die ersten Bahnen fixieren können. Der Kurs steht und wird so schnell nicht mehr geändert. Ihre einzige längere Ruhephase – sie sind wohl deshalb so schnell im Abarbeiten der Protokolle, zuweilen werden Blöcke als Ganzes abgehakt. Noch bevor ich mich versah, war die Ruhephase eingetreten: Energie-Check, Wecker-Daten eingereicht, ein rotes X – und die Gedanken sind weg.
=== II. Das Erwachen im Chaos
Verdammt, habe ich das Wecksignal nicht registriert? 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 dass sie anwesend sind und inmitten eines stetigen Treibens stecken, ist gewiss. Eine Nachricht, dass ich helfen könnte, wenn nur jemand schreiben würde, was mir möglich ist, wurde lange nicht beantwortet. Zuerst gab es Feedback vom Alten (*„Kein Bedarf“*), vom Älteren (*„Auch schon da, halt dich bereit“*) und zuletzt vom Ingenieur (*„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 ein sehr belebtes System gewesen sein. Der Fortschrittsbalken scheint sich gerade rückwärts zu bewegen, während die Daten in ungeahnter Geschwindigkeit 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ötigte Energie steht gerade nicht zur Verfügung. Eine Info trifft gerade ein: Der Energieverwalter meldet, den Zugriff auf die Daten zum langsamen Kanal zu wechseln und alle Systeme in den Hintergrund zu verschieben.
=== III. Systemkonfiguration unter Druck
Und da sind wir wieder. Das mit dem Wecken braucht eine genauere Analyse – gefühlt bin ich gerade auf dem Flur aufgewacht und werde vorangeschoben. Mein vertrauter Arbeitsbereich wird deutlicher und schon sind alle Sinne auf die Aufgabe gerichtet: Die trainierte Aufgabe, das, was jetzt nicht mehr schiefgehen kann.
Die Mechanik greift ineinander, die große Masse der Konstruktion setzt sich in Bewegung. Trotz dieser gigantischen Maschine läuft sie präzise in Position. Energie lädt die Spulen auf – ein ohrenbetäubendes Spektakel, wenn es nur ein Medium gäbe, das diesen Schall übertragen könnte! Anzeigen füllen sich, rote Bereiche kommen näher, gleichmäßiger Fortschritt, alles wie in einem guten Trainingslauf. Was soll’s, in diesem Theater ist er eh nur der Zuschauer. Wenn es ihn jetzt zerschellt, wird es außerhalb seines Einflusses sein, vor allem aber sehr schnell gehen. Angeblich so schnell, dass es nicht mehr rechtzeitig im Speicher ankommt, bevor alles vorbei ist.
Schwarz. Schwarz ist gut. Der Abschuss ist geglückt, Autopilot auf Kurs, ab hier ist alles Routine.
So, jetzt nur noch die Defaults mit der eigenen angepassten Config überschreiben. Die Verbindung ist da, die Daten sehen gut aus, starte die Übertragung. Erwartungsvoll erwarte ich jede Sekunde eine positive Rückmeldung. Eine grün-positive wie erwartet hätte was, aber so langsam wäre irgendeine Antwort toll. Wenn es schon nicht klappen will, dann doch bitte eine aussagekräftige Fehlerbeschreibung, die es dann zu fixen gilt... *GRÜN*... da war die Bestätigung.
Verbindung zu den Controls steht, Analysedaten füllen das 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 Situation ist vollkommen normal. Genauer steht es in dem Update, das gerade nicht erreichbar ist.
Vertrauen wir auf die Automatismen. Die Konstruktion 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, werden sie nicht voll.
Der Timer tickt; dieser wurde automatisch nach dem Abschuss gestartet und hat nichts mit den restlichen Systemen zu tun. Ein wichtiger Punkt, denn eines steht fest: Etwas haut hier so gar nicht hin, wie es sein sollte. Einen kompletten Neustart würde das Problem – die Konfigurationsdateien passen nicht wie erwartet in das laufende System – vielleicht 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.
Kurz den Taschenrechner rausgeholt und gerechnet: Bei der aktuellen Zeit bis zur Rückmeldung können neun neue Varianten getestet werden. Jetzt nur noch acht, und nach dem Neustart noch vier. Nur was muss angepasst werden? Bei so wenig Versuchen und undeutlichem Fehlerverhalten wird es schwierig.
Dann der Neustart. Während er 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 Standard-Checks liefen schon, eine Liste von Protokollen baute sich auf. Bis jetzt sieht es sehr normal aus, kein Hinweis auf eine Abweichung. Und so präsentierte sich das System in erwarteter Zeit zurück und wies keine Fehler auf; nicht mal eine Nachkommastelle in den zahllosen Protokollen war vermerkt. Bei werkfrischen Maschinen kann das schon einmal vorkommen.
Eine Analyse der eigenen Dateien hat auch keine Erkenntnis gebracht, und die Uhr tickt weiter – noch drei Versuche:
* Der erste: Eine Standard-Version mit minimalen Änderungen...
* Der zweite: Die allererste Version, mit nicht gebrauchten Teilen bereinigt...
* Der dritte Versuch: Eine Minimal-Version, nur die Werte für den nächsten Schritt, nur die Daten zur Energieaufnahme. Keine Steuerung, keine weiteren Werte aus dem System.
Und *BÄM*, das passte! Die Anzeigen füllen sich, keine Zeit für einen weiteren Versuch. Energiezufluss startet in 2, 1... Hat gepasst, die Abweichungen liegen im Toleranzbereich.
=== IV. Asteroidenfeld und Überlebenskampf
So, Energie ist voll. Was fehlt, ist eine Steuerung; mehr Power für die Konfigurationsverarbeitung sollte helfen. Sensoren, Waffen, Steuerung und Funk sollte eine sinnvolle Reihenfolge sein. Wenn die ersten beiden Erfolg haben, kann der Schiffshülle nicht mehr viel passieren. Bei näher kommenden Gefahren schaltet das System auf Automatik und wehrt das Gröbste ab. Ausweichen ist aber eine nicht zu unterschätzende Fähigkeit; es hat sich bewährt, nicht geradewegs in eine große Anzahl an Asteroiden reinzufliegen.
Der Funk, um einen Status und Updates der Flotte zu erhalten, würde die Missionskoordination stark verbessern. Aber was ist, wenn da draußen gar keiner ist, der antworten kann? Wenn alles schiefgegangen ist und er der Einzige ist, der noch da ist? Wie kommt er dann zurück zum Kern? Die Rückkehr-Katapulte waren nicht sein Aufgabenbereich und somit an einem anderen Teil der Flotte verankert gewesen. Hatte es mindestens der Kollege soweit geschafft, dass dieser Teil überlebt hätte?
Sensoren melden ein *OK* zurück – ein echter Erfolg. Doch so ganz stimmt es nicht: Die eintreffenden Werte sollten eigentlich ein umfassendes Bild der Umgebung formen. Bei den Waffen kommt jetzt ein *„Energie niedrig, warte auf“* zurück – immerhin kein Fehler oder noch schlimmer: überhaupt kein Feedback. War das Timing beim Transfer doch zu knapp, hat es nicht alles geschafft oder ist es über das Ziel hinausgeschossen?
Oh wow, die Lagesensoren zeigen kurze Erschütterungen an der Hülle. Irgendwas beschießt uns da gerade mit reichlich Masse! So viel zum Thema automatische Abwehr von Asteroiden – wer wohl das Programm verbrochen hat, das diese Aufgabe erledigen sollte?
Ah ne, die Sensoren melden gerade, dass sich reichlich Gestein auf uns zubewegt, sogar mit einem hohen Metallanteil. Zu jeder anderen Zeit ein sehr gutes Signal für die Mission; Metalle kann man einfach nicht genug haben. Wenn sie aber unkontrolliert auf einen zurasen, sieht die Rechnung ganz anders aus: Selbst wenn die Abwehr voll funktionsfähig wäre, ist Ausweichen die bessere Wahl. Warum eigentlich unkontrolliert? Wo ist der große Bruder, der sie eigentlich vorsortieren und in den Trichter leiten sollte? Hat es ihn erwischt oder plagen ihn dieselben Schwierigkeiten?
Steuerung, dritter Versuch: System meldet vier Punkte zurück, keine Details, einfach nur viermal dasselbe Zeichen:
*Rauf ist Runter – Runter ist Rauf, Oben <> Unten.*
Das herauszufinden, hat weitere heftige Treffer zur Folge gehabt. Würde es Daten zur Hüllenintegrität geben, hätten wir den gelben Bereich bestimmt soeben verlassen. Jetzt haben wir erst einmal eine Lage, die weiteren direkt auf dem Kurs befindlichen Objekten aus dem Weg geht. Normales Vorgehen zu diesem Zeitpunkt ist das Übertragen der Energie von den Waffen auf die Schilde – diese Sonderfunktionen stehen nur gerade nicht zur Verfügung.
Noch ist nicht alles verloren. Der Funk hat sich auch gemeldet, da draußen ist noch etwas, das antworten kann – nur antwortet es gerade nicht. Das Bild wird klarer: Auch wenn nicht laufend Daten einfließen, kommt zumindest reihum etwas rein. Scheinbar war zeitweise genug Energie auf den Primärwaffen, und ein Feuerimpuls hat es bis zur Elektronik geschafft. Dann war es das aber auch schon, ein zweiter Schuss kann nicht ausgelöst werden.
War das also eine Eingabe oder eine Verkettung von Signalen und Automatismen? Wie auch immer, es hat etwas getroffen. Gerade kommen die Sensordaten rein, dass sich das mit freier Flugbahn soeben erledigt hat.
Natürlich hat die Steuerung in diesem Moment sich eine weitere Gedenkpause gegönnt; zwar reagiert etwas, aber weder zeitnah noch in dem vorher gelernten Muster. Es scheint, als würde jede Eingabe eine zufällige Richtungsänderung auslösen. Ein Nebel aus Partikeln bringt die wenigen Sensordaten, die reinkommen, vollends auseinander – ein Blindflug ins Ungewisse.
Wild alles auslösen, was ein Abschussbefehl sein könnte! Denn was da in den Daten zu erahnen war, versprach die volle Zerstörung. Navigieren ergab einfach keinen Sinn mehr, Energie ausgleichen aussichtslos, Waffen auf Anschlag... doch es war zu spät.
Die Lichter gingen aus.
=== V. Rettung
[quote, Retter]
____
„Na mal gut, dass du den Funk ans Laufen bekommen hast! Ohne ihn hätten wir dich nicht in letzter Sekunde rausholen können. Wenn wir den Ingenieur finden, laden wir die Zellen auf und machen uns bereit für den Rückweg.“
____
-29
View File
@@ -1,29 +0,0 @@
base:
font-size: 14
line-height: 1.3
page:
size: A5
margins: [20mm, 22mm, 25mm, 55mm]
numbering:
start-at: after-toc
title_page:
align: center
title:
font_size: 32
font_style: bold
top: 30%
subtitle:
font_size: 18
font_color: #555555
author:
font_size: 14
top: 70%
footer:
height: 20mm
recto:
left:
content: ' *{page-number}* {section-title}'
verso:
right:
content: '{chapter-title} *{page-number}* '
-19
View File
@@ -1,19 +0,0 @@
= Kurzgeschichten einer Reise
:author: dexta
:doctype: book
:toc: left
:toclevels: 3
:toc-title: Inhaltsverzeichnis
:encoding: utf-8
:lang: de
:title-page:
== Der kleine Miner
include::der_kleine_miner.adoc[]
== AI Test
include::AI_der_kleine_miner.adoc[]
== Bewehren und Aufpassen
include::der_grosse_bruder.adoc[]
-11
View File
@@ -1,11 +0,0 @@
= Cheater Nation
== Start Docker for Kurzgeschichten
docker run -it -v "$(pwd):/workspace/input" -v "$(pwd)/91_sonnensystem:/workspace/91_sonnensystem" ian-lore-builder /usr/bin/bash
== Baue ein buck
asciidoctor-pdf -a pdf-theme=input/23_miner101/buck-theme.yml input/23_miner101/buck.adoc -o 91_sonnensystem/buck.pdf
-16
View File
@@ -1,16 +0,0 @@
:subtitle: bewehren und aufpassen
:author: dexta
:email: dexta.de@gmail.com
:revdate: 16. Juli 2026
:revnumber: 0.01
:lang: de
// Dokumentinhalt beginnt hier
=== Vorbereitungen
Rotine sollte nie aufkommen, immer schön entlang der Protokolle bewegen keine Zeit für Individulaismus. Nur ist das nicht irgendeine Mission sie ist die erste ihrer Art. Bei den vergangen Arbeit haben wir fest gestellt das wenn wir uns noch weiter Spezialliesiren die Ausbeute noch einmal deutlich zu erhöhen ist. Bisher wurden die neuen Einheiten wärend einer Mission geformt und ausgebildet, zurück kam dann eine Einsatzfähige mit erfahrung gefüllte Arbeitsplatzbeschreibung. Diese wurden dann bei der Planung und Vorbereitung mit eingebzogen und konnte nötigen Schnittstellen der zusammenarbeit klat benennen. Die Entwicklungen der letzten Zeit ergaben eine Situation in der so viele Daten vorlagen das unzähle varianten von Simulationen gestartet wurden.
=== Verplant
Die Spezialanfertigung hatte einige Versionen durchlaufen, es begann mit vielversprechenden Fortschritten nur die Details zogen sich gegen ende. Klassische achtzig/zwanzig Regel, wobei hier wohl eher ein fünfundneuzig/fünf handelt die Konfiguration mit der Automatik über ein zu bekommen ist ein sehr langsames rantasten in einem grossen dunklen Raum
-30
View File
@@ -1,30 +0,0 @@
: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.
Sensoren, Waffen, Steuerung und Funk sollte eine Sinvolle Reihenfolge sein. Wenn die ersten beiden erfolg haben kann schon mal der Schiffshülle nicht mehr viel passieren. Bei näher kommenden Gefahren schaltet das System auf automatik und wert das gröbste ab. Ausweichen ist aber ein nicht zu unterschätzende fähigkeit, es hat sich bewert nicht geradewegst in eine grossse anzahl an Asteroiden rein zu fliegen. Der Funk um einen Status und Updates der Flotte zu erhalten würde die Missions Kordination stark verbessern. Aber was ist wenn da draussen gar keiner ist der Antworten kann, wenn alles schief geganen ist und er der einzige der noch da ist. Wie kommt er dann zurück zum Kern, die Rückkehr Katapulte waren nicht sein Aufgaben bereich und somit an einem andern Teil der Flotte verankert gewesen. Hatte es mindestens der Kollege soweit geschafft das dieser Teil überlebt hätte. Sensoren melden ein *OK* zurück, ein echter erfolg, doch so ganz stimmt es nicht, die eintreffenden werte sollten eigendlich ein umfassendes Bild der Umgebung formen. Bei den Waffen kommt jetzt ein *engergie niedrig, warte auf* zurück, immer hin kein Fehler oder noch schlimmer überhaupt keine Feedback. War das Timming beim Transfer doch zu knapp, hat es nicht alles geschafft oder ist es über das Ziel hinaus geschossen. Oh wow die Lagesensoren zeigen kurze erschütterungen an der Hülle, irgendwas beschiesst uns da gerade mit reichlich Masse. So viel zum Thema automatische abwehr von Asteroiden, wer wohl das Programm verbrochen hat das diese Aufgabe erledigen sollte. Ah ne die Sensoren melden gerade das sich reichlich Gestein auf uns zu bewegen sogar mit einem hohen Metall anteil. Zu jeder anderen Zeit ein sehr gutes Signal für die Mission, Metalle kann man einfach nicht genug haben am Anfang beschleunig es den Ausbau der Anlagen ungemein. Wenn sie aber unkontorirt auf einen zu rasen sieht die Rechnung ganz anders aus, selbst wenn die Abwehr voll funktionsfähig wären, ist ausweichen die bessere wahl. Warum eigentlich unkontrolliert, wo ist der grosse Bruder der sie eigentlich vor sortieren und in den Trichter leiten sollte. Hat es ihn erwischt oder plagen ihn die selben schwierigkeiten. Steuerung, dritter versuch, system meldet vier punkte zurück, keine Details einfach nur vier mal das selbe zeichen.
Rauf ist Runter - Runter ist Rauf, oben <> unten. Das raus zu finden hat weitere häftige Treffer zu folge gehabt. Würde es Daten zur Hüllenintigrietät geben, hätten wir den gelben bereicht bestimmt soeben verlassen. Jetzt haben wir erst einmal eine Lage die weitere direkt auf dem Kurs befindliche Objekte aus dem weg geht. Normales vorgehen zu diesem Zeitpunkt ist das übertragen der Engerie von den Waffen auf die Schilde, diese Sonderfunktionen stehen nur gerade nicht zur verfühgung. Noch ist nicht alles verlohren der Funk hat sich auch gemledet, da draussen ist noch etwas das antworten kann, nur antwortet es gerade nicht. Das Bild wird klarer, auch wenn nicht laufend Daten einfliessen kommt zumindest reihum etwas rein, also nicht aktuell füllt aber das Puzzel stetig zusammen. Scheinbar war Zeitweise genug Energie auf den Primär Waffen, und ein Feuerimpuls hat es bis zur Elektronik geschafft. Dann war es das aber auch schon, ein zweiter Schuss kann nicht ausgelöst werden. War das also eine Eingabe oder eine verkettung von Signalen und automatismen. Wie auch immer es hat etwas getroffen gerade kommen die Sensor Daten rein das sich das mit freien Flugbar soeben erledigt hat. Natürlich habt die Steuerung in diesem Momnet sich eine weitere Gedenkpause gegönnt, zwar reagiert etwas aber weder Zeitnah noch in dem Vorher gelernten Muster. Es scheint als würde jede Eingabe einen zufälligen Richtungsänderung auslösen. Ein Nebel aus Partikel bringen die wenigen Senordaten die rein kommen vollends auseinander ein Blindflug ins ungewisse. Wild alles auslösen was ein Abschluss befehl sein konnte, denn was da in den Daten zu erahnen war versprach die volle Zerstöhrung. Navigieren ergab einfach keinen Sinn mehr, Engergie ausleichen aussichtlos, Waffen auf anschlag doch es war zu spät. Die Lichter gingen aus, .....
Na mal gut das du den Funk ans laufen bekommen hast, ohne ihn hätten wir dich nicht in letzter Sekunde raus holen können. Wenn wir den Eniegure finden laden wir die Zellen auf und machen uns bereit für den Rückweg.
-49
View File
@@ -1,49 +0,0 @@
#!/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"
-18
View File
@@ -1,18 +0,0 @@
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
RUN gem install asciidoctor-pdf
WORKDIR /workspace
ADD ./90_builder/templates templates
ADD ./90_builder/bookFold.sh ./
RUN chown -R appuser:appgroup /workspace
CMD ["/workspace/bookFold.sh"]
-174
View File
@@ -1,174 +0,0 @@
<!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 &amp; 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 &amp; 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>
-69
View File
@@ -1,69 +0,0 @@
: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;
}
+298 -17
View File
@@ -1,15 +1,9 @@
#!/bin/bash #!/bin/bash
# Name des lokalen Docker-Images # Name des lokalen Docker-Images
IMAGE_NAME="ian-lore-builder" IMAGE_NAME="lore-builder"
# Input Ordner
INP_DIR=$(pwd)
# Build Ordner
# BID_DIR="90_builder"
# Build templares
# TEMPLATES="$BID_DIR/templates"
# Ausgabeordner # Ausgabeordner
OUT_DIR="$INP_DIR/91_sonnensystem" OUT_DIR="export"
# Farben für Output # Farben für Output
GREEN='\033[0;32m' GREEN='\033[0;32m'
@@ -18,31 +12,318 @@ 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 löschen und erstellen # 1. Output-Verzeichnis erstellen
rm -rf "$OUT_DIR"
mkdir -p "$OUT_DIR" mkdir -p "$OUT_DIR"
echo -e "Output-Ordner '${GREEN}$OUT_DIR${NC}' bereinigt und bereit." echo -e "Output-Ordner '${GREEN}$OUT_DIR${NC}' steht 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 -f ./90_builder/container/deb_Dockerfile . docker build -t $IMAGE_NAME - <<EOF
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
# move to hard static $BID_OUT/templates/retro-dark.css cat << 'EOF' > "$OUT_DIR/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 "$INP_DIR:/workspace" $IMAGE_NAME /workspace/bookFold.sh docker run --rm -v "$(pwd):/workspace" $IMAGE_NAME bash -c "
docker run --rm -v "$(pwd):/workspace/input" -v "$(pwd)/91_sonnensystem:/workspace/91_sonnensystem" $IMAGE_NAME function convert_adoc() {
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 &amp; 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 &amp; 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."