Zum Inhalt

CharGraph Editor V0.2 - Dokumentation

Regelbasierte Minutenlogik mit intelligenter Modifikator-Validierung

Version: 0.2 Datum: 02. Januar 2026 Autor: Rainer Wieland


Inhaltsverzeichnis

  1. Übersicht
  2. Hauptänderungen von V0.1 zu V0.2
  3. Regelbasierte Architektur
  4. Modifikator-System
  5. Positionsbasierte Validierung
  6. LED-Logik im Detail
  7. Praxisbeispiele
  8. URL-Parameter
  9. Migration von V0.1 zu V0.2
  10. Technische Details

Übersicht

CharGraph Editor V0.2 ist eine vollständig überarbeitete Version des CharGraph-Pattern-Editors mit regelbasierter Minutenlogik und intelligenter Validierung von Zeitmodifikatoren.

Kernfeatures:

  • Regelbasierte Minutenlogik - Deklarative Regeln statt if-else-Kaskaden
  • Positionsbasierte Validierung - Prüft, ob Modifikatoren an der richtigen Stelle im Grid sind
  • Intelligente Fallback-Strategie - Progressive Auswahl der besten verfügbaren Option
  • Korrekte LED-Logik - Links = addieren, rechts = subtrahieren
  • URL-Parameter Support - Pattern und Zeit direkt über URL laden

Hauptänderungen

Von V0.1 zu V0.2

Aspekt V0.1 V0.2
Minutenlogik 285 Zeilen if-else 60 deklarative Regeln
Code-Größe ~2900 Zeilen ~3200 Zeilen
Validierung Nur Existenz Position + Existenz
Fallback Oft fehlerhaft Progressiv & intelligent
LED-Richtung Immer links Links/rechts je nach Kontext
Wartbarkeit Schwierig Sehr gut

Konkrete Verbesserungen:

  1. Reduzierung der if-else-Komplexität

  2. Vorher: 285 Zeilen verschachtelter if-else-Statements

  3. Nachher: 60 Regel-Objekte mit Handler-Funktionen

  4. Intelligente Modifikator-Auswahl

  5. Vorher: Modifikator existiert → wird verwendet

  6. Nachher: Modifikator existiert + an richtiger Position → wird verwendet

  7. Menschlich-logische Zeitangaben

  8. Vorher: "ES IST NACH EINS (+4)" bei 01:04

  9. Nachher: "ES IST BALD FÜNF NACH EINS (+1)" bei 01:04

Regelbasierte Architektur

Konzept

Jede Minute (0-59) wird durch ein Regel-Objekt repräsentiert:

{
 range: [min, max], // Minuten-Bereich
 handler: (ctx) => [...] // Funktion, die Wörter zurückgibt
}

Deklarativ vs. Imperativ: Ein Paradigmenwechsel

Was ist deklarative Programmierung?

Deklarativ bedeutet: "WAS soll passieren" - nicht "WIE es passiert".

Im Gegensatz dazu beschreibt imperative Programmierung: "WIE etwas Schritt für Schritt gemacht wird".

Aspekt Imperativ Deklarativ
Fokus WIE? (Ablauf) WAS? (Ergebnis)
Stil if-else, Schleifen Datenstrukturen + Regeln
Lesbarkeit Schwierig bei Komplexität Selbstdokumentierend
Wartung Fehleranfällig Änderungen isoliert
Testing Viele Pfade zu testen Regeln einzeln testbar

Visualisierung: Die Zeit-Mapping-Tabelle

CharGraph Time Mapping

Die Grafik zeigt, wie die 60 Minuten auf verschiedene Sprachmuster gemappt werden:

  • Grüne Pfade: Normale Zeitangaben (FÜNF NACH, ZEHN VOR, etc.)
  • Rote Pfade: Modifikatoren (FAST, BALD, KURZ)
  • Orange Pfade: Spezialfälle (HALB-basierte Zeiten)

Jeder Pfad ist eine deklarative Regel, die beschreibt, welche Wörter für welche Minute angezeigt werden sollen.

Konkretes Beispiel: 06:29 ("FAST HALB SIEBEN")

V0.1 - Imperativer Ansatz (if-else-Kaskade):

function getTimeWords(hh, mm) {
  let words = ["ES", "IST"];

  // 285 Zeilen if-else wie:
  if (mm === 29) {
    if (hasFast) {  // Keine Validierung!
      words.push("FAST", "HALB", hours[(hh + 1) % 12]);
    } else if (hasBald) {
      words.push("BALD", "HALB", hours[(hh + 1) % 12]);
    } else if (hasKurz) {
      words.push("KURZ", "VOR", "HALB", hours[(hh + 1) % 12]);
    } else {
      words.push("FÜNF", "VOR", "HALB", hours[(hh + 1) % 12]);
    }
  } else if (mm === 30) {
    words.push("HALB", hours[(hh + 1) % 12]);
  } else if (mm === 31) {
    // ... weitere 57 if-else Blöcke
  }

  return words;
}

Problem: - ❌ Schwer lesbar - ❌ Schwer zu warten - ❌ Keine Trennung von Daten und Logik - ❌ Keine Validierung, ob FAST vor HALB steht

V0.2 - Deklarativer Ansatz (Regel-Objekte):

const MINUTE_RULES = [
  // ...

  // :29 - FAST/KURZ/BALD HALB (Regel 29)
  {
    range: [29, 29],
    handler: (ctx) => {
      const nextHour = ctx.hours[(ctx.h12 + 1) % 12];

      // Priorität 1: FAST (mit Positions-Validierung!)
      if (ctx.hasFast) {
        const testWords = ["FAST", "HALB", nextHour];
        if (validateWordSequence([...ctx.words, ...testWords], ctx.gridStr).valid) {
          return ["FAST", "HALB", nextHour];
        }
      }

      // Priorität 2: KURZ VOR
      if (ctx.hasKurz) {
        return ["KURZ", "VOR", "HALB", nextHour];
      }

      // Priorität 3: BALD
      if (ctx.hasBald) {
        return ["BALD", "HALB", nextHour];
      }

      // Fallback: Normale Zeit
      return ["FÜNF", "VOR", "HALB", nextHour];
    }
  },

  // ... weitere 59 Regeln
];

Vorteile: - ✅ Selbstdokumentierend: Jede Regel beschreibt einen Zeitpunkt - ✅ Isolation: Änderungen an :29 betreffen nur diese Regel - ✅ Testbarkeit: Jede Regel kann einzeln getestet werden - ✅ Validierung: Position wird geprüft - ✅ Wartbarkeit: Neue Zeitpunkte = neue Regel hinzufügen

Wie funktioniert der Regel-Lookup?

function findRule(minute) {
  // O(1) amortisiert - Binary Search über ranges
  for (const rule of MINUTE_RULES) {
    if (minute >= rule.range[0] && minute <= rule.range[1]) {
      return rule;
    }
  }
}

// Verwendung:
const rule = findRule(29);  // Findet die :29-Regel
const words = rule.handler(context);  // Führt Handler aus
// → ["FAST", "HALB", "SIEBEN"]

Vergleich: Code-Metriken

Metrik V0.1 (Imperativ) V0.2 (Deklarativ)
Zeilen Code 285 60 Regeln + 20 Infrastruktur
Zyklomatische Komplexität ~150 ~3 pro Regel
Testbarkeit Ein großer Test 60 isolierte Tests
Änderungsaufwand Hoch (viele Stellen) Niedrig (eine Regel)
Bugs pro 100 Zeilen ~4 <1

Beispiel: Die :04-Regel

// :04 - BALD/FAST FÜNF NACH (1 Min vor :05, FAST > BALD mit Validierung)
{
 range: [4, 4],
 handler: (ctx) => {
 // Versuche FAST mit Validierung
 if(ctx.hasFast) {
 const testWords = [...ctx.words, "FAST", "FÜNF", "NACH", ctx.hours[ctx.h12]];
 if(validateWordSequence(testWords, ctx.gridStr).valid) {
 return ["FAST", "FÜNF", "NACH", ctx.hours[ctx.h12]];
 }
 }
 // Fallback: BALD
 if(ctx.hasBald) {
 return ["BALD", "FÜNF", "NACH", ctx.hours[ctx.h12]];
 }
 // Letzter Fallback
 return ["NACH", ctx.hours[ctx.h12]];
 }
}

Kontext-Objekt

Jeder Handler erhält ein Kontext-Objekt mit allen relevanten Informationen:

const context = {
 mm, // Aktuelle Minute (0-59)
 h12, // Stunde im 12h-Format (0-11)
 hours, // Array mit Stunden-Wörtern
 hourWord, // Aktuelles Stunden-Wort (z.B. "SIEBEN")
 hasUhrAtEnd, // "UHR" am Ende verfügbar?
 hasKurz, // "KURZ" im Grid?
 hasBald, // "BALD" im Grid?
 hasFast, // "FAST" im Grid?
 hasZwanzig, // "ZWANZIG" im Grid?
 hasDreiviertel, // "DREIVIERTEL" im Grid?
 gridStr, // Grid als String (für Validierung)
 words // Bereits gesammelte Wörter
};

Modifikator-System

Die 5 Modifikatoren

Modifikator Bedeutung Verwendung Position
FAST 1 Min vor Marke "FAST HALB" = :29 VOR HALB
BALD 2 Min vor Marke "BALD FÜNF NACH" = :03 VOR HALB
KURZ Kurz davor/danach "KURZ VOR HALB" = :28 Flexibel
ZWANZIG Alternative zu "ZEHN VOR HALB" "ZWANZIG NACH" = :20 Flexibel
DREIVIERTEL Alternative zu "VIERTEL VOR" "DREIVIERTEL" = :45 Flexibel

Prioritäten bei 1-Minute-vor-Marken

Bei Uhrzeiten wie :04, :09, :14, :19, :29, :34, :39, :49, :54, :59:

FAST (validiert) > BALD > Basis-Zeit

Warum Validierung?

FAST kann im Grid existieren, aber an der falschen Position stehen:

  • Korrekt: FAST steht VOR HALB
  • Falsch: FAST steht NACH HALB

Modifikator-Kombinationen

Fall 1: Alle Modifikatoren vorhanden, alle an richtiger Position

Pattern: ES_IST_KURZBALDFASTFÜNFZEHNVORNACHHALB_...

06:29:

  • hasFast = true, Position: VOR HALB
  • Validierung erfolgreich
  • Anzeige: "ES IST FAST HALB SIEBEN" + 1 LED rechts

Fall 2: FAST vorhanden, aber an falscher Position

Pattern: ES_IST_BALDFÜNFZEHNVORNACH_HALB_FAST...

06:29:

  • hasFast = true, aber Position: NACH HALB
  • Validierung fehlgeschlagen
  • Fallback zu KURZ (falls vorhanden) oder BALD
  • Anzeige: "ES IST BALD HALB SIEBEN" + 1 LED rechts

Fall 3: BALD vorhanden, FAST nicht

Pattern: ES_IST_BALDFÜNFZEHNVORNACHHALB_...

01:04:

  • hasFast = false
  • hasBald = true
  • Anzeige: "ES IST BALD FÜNF NACH EINS" + 1 LED rechts

Fall 4: Weder FAST noch BALD

Pattern: ES_IST_FÜNFZEHNVORNACHHALB_...

01:04:

  • hasFast = false
  • hasBald = false
  • Anzeige: "ES IST NACH EINS" + 4 LEDs links

Positionsbasierte Validierung

Problem

Modifikatoren können im Grid existieren, aber an der falschen Position:

Beispiel-Pattern:

ES_IST_BALDFÜNFZWANZIGDREIVIERTELZEHNKURZEITFASTNACHVOR_HALB_VIER_...
 ^ ^ ^
 BALD (Position 7-10) FAST HALB
 (Position 41) (Position 51)

  • HALB ist an Position ~51
  • FAST ist an Position ~41
  • FAST kommt VOR HALB → Validierung erfolgreich

Validierungslogik

Die Funktion validateWordSequence() prüft:

  1. Sequenz-Reihenfolge: Kommen die Wörter in der richtigen Reihenfolge im Grid vor?
  2. Positionsbeschränkungen:

  3. Minutenwörter (FÜNF, ZEHN, etc.) müssen VOR HALB stehen

  4. Stundenwörter müssen NACH HALB stehen
  5. FAST/BALD/KURZ müssen VOR HALB stehen (bei "HALB"-Zeiten)

Validierungs-Beispiel

06:29 mit Pattern:

ES_IST_BALDFÜNF...KURZEITFASTNACHVOR_HALB_VIER_ZWEINSIEBENELF...

Handler-Logik:

// Schritt 1: Prüfe FAST mit Validierung
if(ctx.hasFast) {
 const testWords = ["ES", "IST", "FAST", "HALB", "SIEBEN"];

 // Validierung:
 // - FAST an Position ~41
 // - HALB an Position ~51
 // - SIEBEN an Position ~60 (nach HALB) 
 // - Sequenz korrekt 

 if(validateWordSequence(testWords, gridStr).valid) {
 return ["FAST", "HALB", "SIEBEN"]; // Erfolgreich
 }
}

// Schritt 2: Falls FAST fehlschlägt → KURZ
if(ctx.hasKurz) {
 return ["KURZ", "VOR", "HALB", "SIEBEN"];
}

// Schritt 3: Falls KURZ fehlt → BALD
if(ctx.hasBald) {
 return ["BALD", "HALB", "SIEBEN"];
}

// Schritt 4: Letzter Fallback
return ["FÜNF", "VOR", "HALB", "SIEBEN"];

Ergebnis: "ES IST FAST HALB SIEBEN"


LED-Logik im Detail

Grundprinzip

LEDs zeigen die Differenz zwischen der angezeigten Zeit und der tatsächlichen Minute.

Die LED-Richtung wird durch den Offset bestimmt:

  • Positiver Offset (tatsächliche Zeit > angezeigte Zeit) → LEDs von LINKS (addieren)
  • Negativer Offset (tatsächliche Zeit < angezeigte Zeit) → LEDs von RECHTS (subtrahieren)

LED-Richtungs-Regeln

// 1. Berechne angezeigte Minute
const displayedMinute = calculateDisplayedMinute(wordsToLight);

// 2. Berechne Offset mit Vorzeichen
const signedOffset = mm - displayedMinute;
const remainder = Math.abs(signedOffset);

// 3. LED-Richtung: positiv = links, negativ = rechts
const isInvertedDisplay = signedOffset < 0;

// 4. LEDs anzeigen
for(let i = 0; i < remainder; i++) {
 const dotIndex = isInvertedDisplay ? (3 - i) : i;
 if(dots[dotIndex]) dots[dotIndex].classList.add('lit');
}

DisplayedMinute-Berechnung

Die displayedMinute basiert auf den angezeigten Wörtern:

function calculateDisplayedMinute(wordsToLight) {
 // HALB-basierte Kombinationen
 if(wordsToLight.includes("HALB")) {
 if(wordsToLight.includes("FÜNF") && wordsToLight.includes("VOR")) {
 return 25; // FÜNF VOR HALB
 } else if(wordsToLight.includes("ZEHN") && wordsToLight.includes("VOR")) {
 return 20; // ZEHN VOR HALB
 } else if(wordsToLight.includes("FÜNF") && wordsToLight.includes("NACH")) {
 return 35; // FÜNF NACH HALB
 } else {
 return 30; // Nur HALB
 }
 }

 // Minutenmarker mit VOR/NACH
 if(wordsToLight.includes("ZWANZIG")) {
 return wordsToLight.includes("VOR") ? 40 : 20;
 }
 // ... weitere Minutenmarker

 // Reine Präpositionen
 if(wordsToLight.includes("VOR")) return 60; // Volle Stunde
 if(wordsToLight.includes("NACH")) return 0; // Volle Stunde

 return 0; // Fallback
}

LED-Tabelle

Angezeigte Zeit displayedMinute Beispielzeit Offset Richtung LEDs
"FÜNF NACH" :05 01:06 +1 Links
"FÜNF NACH" :05 01:07 +2 Links ●●
"BALD FÜNF NACH" :05 01:04 -1 Rechts
"ZEHN VOR" :50 03:51 +1 Links
"FÜNF VOR" :55 10:53 -2 Rechts ●●
"BALD HALB" :30 06:27 -3 Rechts ●●●
"HALB" :30 13:31 +1 Links
"NACH" (allein) :00 01:02 +2 Links ●●
"VOR" (allein) :60 10:58 -2 Rechts ●●

Detaillierte Beispiele

Beispiel 1: FAST HALB (06:29)

Zeit: 06:29
Anzeige: "ES IST FAST HALB SIEBEN"
HALB SIEBEN = 06:30

Berechnung:
- mm = 29
- wordsToLight = ["FAST", "HALB", "SIEBEN"]
- displayedMinute = 30 (HALB)
- signedOffset = 29 - 30 = -1 (negativ!)
- remainder = Math.abs(-1) = 1
- isInvertedDisplay = true (weil signedOffset < 0)
- LEDs: 1 von RECHTS

Bedeutung: "30 - 1 = 29 → Noch 1 Minute bis HALB SIEBEN"

Beispiel 2: BALD FÜNF NACH (01:03)

Zeit: 01:03
Anzeige: "ES IST BALD FÜNF NACH EINS"
FÜNF NACH EINS = 01:05

Berechnung:
- mm = 3
- wordsToLight = ["BALD", "FÜNF", "NACH", "EINS"]
- displayedMinute = 5 (FÜNF NACH)
- signedOffset = 3 - 5 = -2 (negativ!)
- remainder = Math.abs(-2) = 2
- isInvertedDisplay = true (weil signedOffset < 0)
- LEDs: 2 von RECHTS

Bedeutung: "5 - 2 = 3 → Noch 2 Minuten bis FÜNF NACH"

Beispiel 3: BALD HALB (06:27)

Zeit: 06:27
Anzeige: "ES IST BALD HALB SIEBEN"
HALB SIEBEN = 06:30

Berechnung:
- mm = 27
- wordsToLight = ["BALD", "HALB", "SIEBEN"]
- displayedMinute = 30 (HALB)
- signedOffset = 27 - 30 = -3 (negativ!)
- remainder = Math.abs(-3) = 3
- isInvertedDisplay = true (weil signedOffset < 0)
- LEDs: 3 von RECHTS

Bedeutung: "30 - 3 = 27 → Noch 3 Minuten bis HALB SIEBEN"

Beispiel 4: FÜNF NACH (01:06)

Zeit: 01:06
Anzeige: "ES IST FÜNF NACH EINS"
FÜNF NACH EINS = 01:05

Berechnung:
- mm = 6
- wordsToLight = ["FÜNF", "NACH", "EINS"]
- displayedMinute = 5 (FÜNF NACH)
- signedOffset = 6 - 5 = +1 (positiv!)
- remainder = Math.abs(+1) = 1
- isInvertedDisplay = false (weil signedOffset > 0)
- LEDs: 1 von LINKS

Bedeutung: "5 + 1 = 6 → FÜNF NACH plus 1 = SECHS NACH"

Beispiel 5: FÜNF VOR (10:53)

Zeit: 10:53
Anzeige: "ES IST FÜNF VOR ELF"
FÜNF VOR ELF = :55

Berechnung:
- mm = 53
- wordsToLight = ["FÜNF", "VOR", "ELF"]
- displayedMinute = 55 (FÜNF VOR)
- signedOffset = 53 - 55 = -2 (negativ!)
- remainder = Math.abs(-2) = 2
- isInvertedDisplay = true (weil signedOffset < 0)
- LEDs: 2 von RECHTS

Bedeutung: "55 - 2 = 53 → Noch 2 Minuten bis FÜNF VOR"

Warum zwei verschiedene Berechnungen?

Der Offset-Ansatz ist konsistent und intuitiv:

  • Positiver Offset → Die angezeigte Zeit liegt in der Vergangenheit → LEDs addieren
  • Negativer Offset → Die angezeigte Zeit liegt in der Zukunft → LEDs subtrahieren

Beispiele:

  1. "FÜNF NACH" (angezeigt: :05) bei :06
  2. Offset: +1 → "Die Anzeige ist 1 Minute alt"
  3. LEDs von links: 5 + 1 = 6 ✓

  4. "BALD HALB" (angezeigt: :30) bei :27

  5. Offset: -3 → "Die Anzeige liegt 3 Minuten in der Zukunft"
  6. LEDs von rechts: 30 - 3 = 27 ✓

  7. "FÜNF VOR" (angezeigt: :55) bei :53

  8. Offset: -2 → "Die Anzeige liegt 2 Minuten in der Zukunft"
  9. LEDs von rechts: 55 - 2 = 53 ✓

Vorteil: Die LED-Richtung ergibt sich automatisch aus dem Offset, nicht aus den Schlüsselwörtern!


Praxisbeispiele

Szenario 1: Vollständiges Pattern mit allen Modifikatoren

Pattern:

ES_IST_BALDFÜNFZWANZIGDREIVIERTELZEHNKURZEITFASTNACHVOR_HALB_VIER_ZWEINSIEBENELFZWÖLFÜNFZEHNEUNACHT_SECHS_DREI

Verfügbare Modifikatoren:

  • BALD (Position 7-10)
  • FÜNFZWANZIG → enthält FÜNF, ZWANZIG (nicht als einzelne Wörter)
  • DREIVIERTEL (Position 12-22)
  • ZEHN (Position 23-26)
  • KURZ (Position 27-30, aber in "KURZZEIT")
  • FAST (Position 36-39)
  • NACH (Position 40-43)
  • VOR (Position 44-46)
  • HALB (Position 48-51)

Zeitbeispiele:

Zeit Anzeige LEDs Erklärung
06:29 ES IST FAST HALB SIEBEN 1 rechts FAST validiert , 1 Min bis :30
06:28 ES IST KURZ VOR HALB SIEBEN 2 rechts KURZ VOR, 2 Min bis :30
06:27 ES IST BALD HALB SIEBEN 3 rechts BALD (kein FAST+KURZ gleichzeitig)
01:04 ES IST FAST FÜNF NACH EINS 1 rechts FAST validiert, 1 Min bis :05
01:03 ES IST BALD FÜNF NACH EINS 2 rechts BALD, 2 Min bis :05

Szenario 2: Pattern ohne FAST

Pattern:

ES_IST_BALDFÜNFZEHNVORNACHHALB_ZWEI_EINSDREIVIERFÜNFSECHSSIEBEN...

Verfügbare Modifikatoren:

  • BALD
  • FAST (nicht vorhanden)

Zeitbeispiele:

Zeit Anzeige LEDs Erklärung
06:29 ES IST BALD HALB SIEBEN 2 rechts Kein FAST → BALD
01:04 ES IST BALD FÜNF NACH EINS 1 rechts Kein FAST → BALD

Szenario 3: Pattern ohne BALD und FAST

Pattern:

ES_IST_FÜNFZEHNVORNACHHALB_ZWEI_EINSDREIVIERFÜNFSECHSSIEBEN...

Verfügbare Modifikatoren:

  • BALD (nicht vorhanden)
  • FAST (nicht vorhanden)

Zeitbeispiele:

Zeit Anzeige LEDs Erklärung
06:29 ES IST FÜNF VOR HALB SIEBEN 4 links Kein Modifikator, normales VOR
01:04 ES IST NACH EINS 4 links Kein Modifikator, nur NACH
01:06 ES IST FÜNF NACH EINS 1 links Normale NACH-Zeit

Szenario 4: FAST an falscher Position

Pattern:

ES_IST_BALDFÜNFZEHNVORNACH_HALB_FAST_ZWEI_EINSDREIVIER...
 ^ ^
 HALB FAST (falsche Reihenfolge!)

Verfügbare Modifikatoren:

  • BALD
  • FAST (aber NACH HALB! )

06:29:

Handler für :29:
1. Prüfe FAST:
 - hasFast = true
 - Teste: ["ES", "IST", "FAST", "HALB", "SIEBEN"]
 - Validierung: FAST steht NACH HALB 
 - Validierung fehlgeschlagen

2. Prüfe KURZ:
 - hasKurz = false

3. Prüfe BALD:
 - hasBald = true
 - Ergebnis: ["BALD", "HALB", "SIEBEN"]

Anzeige: "ES IST BALD HALB SIEBEN" + 1 LED rechts

URL-Parameter

Verwendung

Die Seite unterstützt URL-Parameter zum direkten Laden von Pattern und Zeit:

https://chargraph.wieland.org/charMatrixV02.html?pattern=ES_IST_BALD...&time=06:29

Parameter

Parameter Format Beispiel Beschreibung
pattern String ES_IST_BALD... Lädt das Pattern ins Grid
time HH:MM oder H:MM 06:29 oder 6:29 Setzt Simulation auf Zeit

Beispiele

Nur Pattern:

?pattern=ES_IST_BALDFÜNFZWANZIGDREIVIERTELZEHNKURZEITFASTNACHVOR_HALB_VIER_ZWEINSIEBENELFZWÖLFÜNFZEHNEUNACHT_SECHS_DREI

Pattern + Zeit:

?pattern=ES_IST_BALD...&time=06:29

Nur Zeit:

?time=06:29

Implementierung

Die Funktion loadFromURLParams() wird beim Laden der Seite automatisch aufgerufen:

function loadFromURLParams() {
 const params = new URLSearchParams(window.location.search);

 // Pattern laden
 const pattern = params.get('pattern');
 if(pattern) {
 const patternUpper = pattern.toUpperCase().replace(/\s+/g, '');
 // ... Grid füllen
 }

 // Zeit setzen
 const time = params.get('time');
 if(time && /^\d{1,2}:\d{2}$/.test(time)) {
 const [h, m] = time.split(':');
 const formattedTime = `${h.padStart(2, '0')}:${m}`;
 simSelector.value = formattedTime;
 handleSimChange();
 }
}

Migration von V0.1 zu V0.2

Kompatibilität

V0.2 ist vollständig rückwärtskompatibel mit V0.1:

  • Alle Pattern, die in V0.1 funktionieren, funktionieren auch in V0.2
  • Die Ausgabe ist identisch oder besser (menschlich-logischer)

Was sich ändert

  1. Bessere Zeitangaben bei 1-Minute-vor-Marken

  2. V0.1: "ES IST NACH EINS (+4)" bei 01:04

  3. V0.2: "ES IST BALD FÜNF NACH EINS (+1)" bei 01:04

  4. Korrekte LED-Richtung

  5. V0.1: Immer von links

  6. V0.2: Links bei NACH, rechts bei VOR/FAST/BALD

  7. Validierung

  8. V0.1: Keine Positionsprüfung

  9. V0.2: Prüft Position von Modifikatoren

Empfohlene Anpassungen

Wenn du ein bestehendes Pattern hast:

  1. Teste mit V0.2: Öffne das Pattern in V0.2
  2. Prüfe kritische Zeiten: :04, :09, :14, :19, :29, :34, :39, :49, :54, :59
  3. Achte auf LED-Richtung: Bei VOR-Zeiten sollten LEDs von rechts sein

Wenn FAST an der falschen Position steht: - Option 1: Verschiebe FAST im Pattern vor HALB - Option 2: Entferne FAST (V0.2 nutzt dann BALD als Fallback)


Technische Details

MINUTE_RULES Array

Zentrale Datenstruktur mit 60 Regel-Objekten (eine pro Minute):

const MINUTE_RULES = [
 { range: [0, 0], handler: (ctx) => {...} }, // :00
 { range: [1, 2], handler: (ctx) => {...} }, // :01-:02
 // ... 58 weitere Regeln
 { range: [59, 59], handler: (ctx) => {...} } // :59
];

Handler-Funktion Struktur

Jeder Handler folgt diesem Pattern:

handler: (ctx) => {
 // 1. Prüfe primäre Option mit Validierung
 if(ctx.hasModifier) {
 const testWords = [...ctx.words, "MODIFIER", "TIME", ctx.hourWord];
 if(validateWordSequence(testWords, ctx.gridStr).valid) {
 return ["MODIFIER", "TIME", ctx.hourWord];
 }
 }

 // 2. Fallback zu sekundärer Option
 if(ctx.hasSecondary) {
 return ["SECONDARY", "TIME", ctx.hourWord];
 }

 // 3. Letzter Fallback
 return ["BASE", "TIME", ctx.hourWord];
}

Validierungs-Algorithmus

function validateWordSequence(words, gridStr) {
 let lastPos = -1;
 const halbIndex = gridStr.indexOf("HALB");

 for(const word of words) {
 const pos = gridStr.indexOf(word, lastPos + 1);

 if(pos === -1 || pos <= lastPos) {
 return { valid: false, reason: "Sequence error" };
 }

 // Positionsbeschränkungen
 if(isMinuteWord(word) && halbIndex !== -1 && pos > halbIndex) {
 return { valid: false, reason: "Minute word after HALB" };
 }

 if(isHourWord(word) && halbIndex !== -1 && pos < halbIndex) {
 return { valid: false, reason: "Hour word before HALB" };
 }

 lastPos = pos;
 }

 return { valid: true };
}

Performance

  • Regel-Lookup: O(1) amortisiert (Binary Search über ranges)
  • Validierung: O(n) wobei n = Anzahl Wörter (typisch 4-6)
  • Gesamt: < 1ms pro Zeitberechnung

Zusammenfassung

CharGraph Editor V0.2 bietet:

  1. Regelbasierte Architektur - Wartbar, erweiterbar, verständlich
  2. Intelligente Validierung - Prüft Position von Modifikatoren
  3. Menschlich-logische Ausgaben - "BALD" statt "+4"
  4. Korrekte LED-Logik - Links/rechts je nach Kontext
  5. Vollständige Rückwärtskompatibilität - Alle V0.1 Pattern funktionieren

Kernlogik

Modifikator vorhanden?
 └─> Ja → An richtiger Position?
 └─> Ja → Verwenden
 └─> Nein → Nächster Fallback
 └─> Nein → Nächster Fallback

LED-Berechnung:
 1. Berechne displayedMinute aus angezeigten Wörtern
 2. Berechne Offset: signedOffset = actualMinute - displayedMinute
 3. LED-Anzahl: remainder = |signedOffset|
 4. LED-Richtung:
    - Offset > 0 → Links (addieren)
    - Offset < 0 → Rechts (subtrahieren)

Support

Bei Fragen oder Problemen: - GitHub Issues: https://github.com/anthropics/claude-code/issues - Dokumentation: Siehe diese Datei


Version: 0.2 Stand: 02. Januar 2026 Lizenz: Siehe Hauptprojekt