Alles auf einer Seite

Alle aktiven Einträge chronologisch am Stück.

6. Juni 2026

Antares Mark-0: Super-GAU-Risiko und Realität

Heute hat der Mikroreaktor Mark-0 von Antares Nuclear in den USA erstmals die Kritikalität erreicht. Im Gegensatz zu herkömmlichen Atomkraftwerken ist ein Super-GAU (eine unkontrollierte Kernschmelze) bei diesem Reaktortyp physikalisch ausgeschlossen. Das liegt an zwei fundamentalen technischen Unterschieden.

1. TRISO-Brennstoff statt Brennstäbe

Klassische Zirkonium-Brennstäbe können schmelzen. Der Mark-0 nutzt stattdessen TRISO: Uran, das in winzige, extrem hitzebeständige Keramik-Kügelchen eingeschlossen ist. Diese Hülle hält Temperaturen von über 1.760 °C stand. Die Kettenreaktion stoppt durch physikalische Gesetze von selbst, lange bevor diese Schmelztemperatur erreicht wird. Der Brennstoff ist somit sein eigener Schutzbehälter.

Exkurs: Woher kommt der Name TRISO? TRISO steht für Tristructural-isotropic. "Tristructural" beschreibt den mehrfachen strukturellen Aufbau der Hülle um den Urankern: eine Schicht aus porösem Kohlenstoff (die wie ein Schwamm Spaltgase auffängt), umgeben von hochdichtem pyrolytischem Kohlenstoff und extrem hartem Siliziumkarbid (Keramik). "Isotropic" (isotrop) bedeutet, dass die Kugel völlig symmetrisch ist. Unter extremer Hitze und radioaktiver Strahlung dehnt sie sich in alle Richtungen exakt gleichmäßig aus, was verhindert, dass die Schale durch mechanische Spannungen reißt.

2. Passive Kühlung

Anstelle von fehleranfälligen Wasserpumpen, die zwingend permanenten Strom brauchen, nutzt der Reaktor passive Natrium-Heatpipes. Fällt der Strom aus, kühlt sich das System rein thermodynamisch von selbst ab. Es gibt kein Wasser, das unter extremem Druck verdampfen und explodieren kann.

Exkurs: Wie funktioniert Kühlen ohne Pumpen? Eine Natrium-Heatpipe (Wärmerohr) nutzt reine Physik statt Mechanik. Sie ist ein hohles, versiegeltes Rohr, in dem ein wenig flüssiges Natrium zirkuliert. Am heißen Reaktorkern verdampft das Natrium, steigt als Gas nach oben zum kälteren Ende, gibt dort die Hitze ab und kondensiert. Durch die Kapillarkraft einer porösen Innenstruktur fließt es dann passiv zurück zum Kern. Es gibt keine beweglichen Teile, keinen Verschleiß und keinen Bedarf an Pumpenstrom.

Die tatsächlichen Restrisiken

Auch ohne Risiko einer Kernschmelze gibt es handfeste Probleme, die berücksichtigt werden müssen:

  • Produktionsfehler: Die Sicherheit hängt von der absolut makellosen Herstellung von Millionen winziger TRISO-Kügelchen ab. Mikrorisse in der Keramik führen dazu, dass radioaktives Gas in den Kühlkreislauf entweicht und das System kontaminiert.
  • Praxistest fehlt: Der Mark-0 ist ein Nullleistungs-Testreaktor. Es gibt weltweit noch keine verlässlichen Langzeitdaten für einen kommerziellen Dauerbetrieb unter Volllast mit diesem spezifischen System.
  • Materialrisiko (Proliferation): Das verwendete HALEU-Uran ist deutlich höher angereichert als üblich.

Exkurs: Das HALEU-Dilemma HALEU steht für High-Assay Low-Enriched Uranium. Standard-Leichtwasserreaktoren nutzen Uran, das auf ca. 3 bis 5 % mit dem spaltbaren U-235 angereichert ist. Für den Bau von Atomwaffen benötigt man über 90 % (Highly Enriched Uranium, HEU). HALEU liegt mit 5 bis 20 % genau dazwischen. Dieser höhere Wert erlaubt zwar die extrem kompakte Bauweise und jahrelange Laufzeiten des Antares-Reaktors ohne Brennstoffwechsel, macht das Material aber geopolitisch sensibler und weitaus attraktiver für Diebstahl.

Fazit

Das Risiko einer unkontrollierten Kernschmelze ist physikalisch eliminiert. Das ist ein messbarer Fortschritt. Die technologische Herausforderung verlagert sich damit von der aktiven Unfallverhinderung durch redundante Notkühlsysteme hin zur fehlerfreien Massenproduktion der Keramik-Brennstoffe und der Diebstahlsicherung des angereicherten Materials.

5. Juni 2026

Alltagsrisiken beim Radfahren: Gefahren nicht unterschätzen

Die meisten Risiken sind bekannt. Kritisch wird es erst, wenn man das alltägliche Umfeld unterschätzt. Die folgenden Punkte und die anschließende Auswertung basieren auf meiner eigenen Erfahrung.


1. Nässe und Kopfsteinpflaster

Nässe und Pflastersteine sind eine miese Kombination. Fahrbahnmarkierungen, Schienen und Kanaldeckel werden bei Regen schlicht zur Schmierseife. Auf feuchtem Kopfsteinpflaster geht die Bodenhaftung vollends gegen Null, das Rad springt und das Profil hat keine Auflagefläche.

2. Niedrige Bordsteine im spitzen Winkel

Wer flache Bordsteinkanten in einem sehr spitzen Winkel anfährt, hebelt sich verlässlich selbst aus. Das Vorderrad klettert nicht, sondern rutscht einfach an der Längskante ab.

3. Schlafmangel

Schlafmangel, Unkonzentriertheit, Reaktionsschnelligkeit reduziert.


Empirische Falldaten und Ereignisanalyse

Zur Veranschaulichung dient die nachfolgende Auswertung der eigenen Fahrleistung.

1. Systemparameter und Exposition

  • Beobachtungszeitraum: 25.08.2025 bis 04.06.2026
  • Gesamtfahrleistung: 5.950 km
  • Inzidenzrate: 2 Sturzereignisse (entspricht ~0,34 Stürzen pro 1.000 km)

2. Ereignisprotokoll

Ereignis 1

  • Szenario: Schräges Überqueren eines niedrigen Bordsteins, ~12 km/h
  • Wetter: Regennasse Fahrbahn bei Regen
  • Spezifischer Risikofaktor: Metall-Begrenzungsausführung der Kante
  • Schutzausrüstung (Hände): Gummierte Handschuhe (nur Handfläche) ohne Fingerknöchel Schutz, leichtes Textil
  • Verletzungsfolge (Körper): Schürfwunden
  • Verletzungsfolge (Hände): Starke Prellung an linkem Handballen und Gewebeschaden am Fingerknöchel des kleinen Fingers

Ereignis 2

  • Szenario: Linksabbiegen in eine Vorfahrtsstraße, ~12 km/h
  • Wetter: Regennasse Fahrbahn, kein Regen
  • Spezifischer Risikofaktor: Verkehrsberuhigter Kopfsteinpflaster-Abschnitt, Schlafmangel in der Nacht davor
  • Schutzausrüstung (Hände): Motorrad-Leder/Textil-Handschuhe
  • Verletzungsfolge (Körper): Rippenprellung, Schürfwunden
  • Verletzungsfolge (Hände): Keine (Schutz durch Protektion)

3. Ende

Beim ersten Ereignis boten die leichten, gummierten Handschuhe unzureichenden Schutz, was bei Bodenkontakt direkt zu einer starken Prellung und Verletzungen an der Hand führte. Immerhin keine Hautverletzung am Ballen aufgrund der Gummierung. Beim zweiten Ereignis kam es trotz höherer Aufprallenergie am Rumpf (Rippenprellung) zu keinen Handverletzungen. Der Leder-Ballenschutz an den Handschuhen hat mir geholfen.

4. Juni 2026

my-homepage: B2B Source License

my-homepage ist der Static Site Generator hinter dieser Website. Das Projekt erzeugt statische HTML-Seiten aus Markdown-Inhalten und enthält Layout, Suche, Inhaltsverzeichnis, SEO-Ausgabe und Build-Logik.

Der Code wird nicht als Open-Source-Projekt veröffentlicht. Angeboten wird eine personenbezogene B2B-Nutzungslizenz mit Quellcodezugang.

Angebot

Das Angebot richtet sich ausschließlich an Unternehmer im Sinne von § 14 BGB. Verbraucher im Sinne von § 13 BGB sind vom Erwerb und von der Nutzung ausgeschlossen.

Mit Bestellung oder Annahme des Angebots bestätigt der Käufer, dass er als Unternehmer handelt und den Erwerb nicht überwiegend zu privaten Zwecken tätigt.

Lizenz

Der Käufer erhält eine einfache, nicht exklusive, nicht übertragbare Nutzungslizenz für einen Nutzer / Seat.

Erlaubt ist:

  • Quellcode lesen, bauen und lokal ändern
  • Nutzung für eigene berufliche Websites des Lizenznehmers
  • Veröffentlichung der erzeugten statischen HTML-Ausgabe

Nicht erlaubt ist:

  • Veröffentlichung oder Weitergabe des Quellcodes
  • Weiterverkauf oder Unterlizenzierung
  • Rebranding als eigenes Produkt
  • Nutzung für Kundenprojekte ohne ausdrückliche Vereinbarung
  • Betrieb eines SSG-, Hosting-, Website-Generator-, SaaS- oder Plattform-Angebots für Dritte

Die Urheberrechte am ursprünglichen Projekt werden nicht übertragen.

Lieferung

Geliefert wird der Quellcode von my-homepage in dem beim Vertragsschluss bereitgestellten oder vereinbarten Stand, digital als ZIP-Archiv, Download oder Repository-Zugang.

Nicht enthalten sind individuelle Anpassung, Hosting, Deployment, Support, Wartung, Rechtsberatung oder Steuerberatung, sofern dies nicht ausdrücklich vereinbart wurde.

Drittkomponenten

Externe Komponenten und Werkzeuge bleiben unter ihren jeweiligen Lizenzen. Mitgelieferte Lizenz- und Copyright-Hinweise bleiben erhalten. Die Lizenz für my-homepage ändert die Rechte an diesen Drittkomponenten nicht.

Preis

Der Preis beträgt 799,00 EUR pro Nutzer / Seat.

Der Betrag ist der zu zahlende Endpreis. Ich wende die Kleinunternehmerregelung nach § 19 UStG an. Deshalb erhebe ich keine Umsatzsteuer und weise sie in der Rechnung nicht gesondert aus. Ein Vorsteuerabzug aus Umsatzsteuer ist daher nicht möglich.

Vertragsschluss

Ein Lizenzvertrag kommt zustande, wenn der Käufer das Angebot annimmt und ich die Annahme in Textform bestätige oder den Quellcode nach Zahlungseingang bereitstelle.

Die Lizenz wird erst nach vollständiger Zahlung eingeräumt, sofern nicht ausdrücklich etwas anderes vereinbart wurde.

Maßgeblich sind diese Beschreibung und die Datei LICENSE.md in der beim Vertragsschluss bereitgestellten Fassung. Bei Widersprüchen gehen ausdrücklich bestätigte individuelle Vereinbarungen vor.

Bestellung

Für eine Bestellung benötige ich Name/Firma, Rechnungsanschrift, E-Mail-Adresse und die Bestätigung, dass der Erwerb als Unternehmer erfolgt.

2. Juni 2026

Fokus und Stille: Bose QuietComfort vs. Sony WH-1000XM4 im reinen ANC-Betrieb

Beim Programmieren oder Architektur-Design ist Stille ein wichtiges Werkzeug. Kopfhörer mit aktiver Geräuschunterdrückung (ANC) sind in diesem Szenario nicht in erster Linie Musikhörer, sondern eher eine Art elektronischer Gehörschutz. Aufsetzen, einschalten, Ruhe. Keine Musik, kein gekoppeltes Smartphone, kein Bluetooth-Gefummel.

Ich habe mir unter diesem eher speziellen Gesichtspunkt zwei Modelle angesehen:

  • Bose QuietComfort (179€)
  • Sony WH-1000XM4 (248€)

Verhalten beim Start (reiner ANC-Modus)

Wenn man einen Kopfhörer nur für Stille nutzt, stören automatische Sprachansagen beim Einschalten über Batteriestand oder Bluetooth-Suche.

Der Sony WH-1000XM4 verhält sich hier von Haus aus ruhig: Das System fährt beim Einschalten ohne Sprache in den ANC-Modus hoch.

Beim Bose QuietComfort ist standardmäßig eine Sprachansage aktiv. Ein Workaround führt hier über die Smartphone-App von Bose: Dort lassen sich die "Voice prompts" auf "Off" stellen. Danach verhält sich der Kopfhörer beim Einschalten ebenfalls unaufdringlich.

Bei der Bedienung gibt es einen kleinen, aber im Alltag spürbaren Unterschied: Der Bose hat für On/Off einen mechanischen Schiebeschalter. Der Zustand ist dadurch direkt sichtbar und haptisch eindeutig. Der Sony nutzt dagegen einen Toggle-Button für On/Off. Das funktioniert ebenfalls, fühlt sich aber weniger mechanisch eindeutig an, weil man den Zustand eher über Reaktion und LED mitbekommt.

Hardware-Features und Anpassung

Ein Unterschied zeigt sich in der Kalibrierung der Geräuschunterdrückung. Der Sony bietet hierfür einen dedizierten Optimizer Mode, der sich über eine Taste an der Hörmuschel aktivieren lässt. Das System spielt kurze Testtöne ab und passt das ANC an die aktuelle Tragesituation (z.B. Brille, Haare) an.

Bose verzichtet auf ein solches manuell auslösbares Optimizer-Feature. Es gibt keine entsprechende Taste und keinen sichtbaren Kalibrierungslauf. Das ANC arbeitet im normalen Betrieb ohne diesen zusätzlichen Schritt.

Geometrie

Der Bose QuietComfort wirkt insgesamt ein klein wenig kompakter. Gleichzeitig ist in den Ohrmuscheln für große Ohren eine kleine Nuance mehr Raum. Das ist kein riesiger Unterschied.

Beim Sony WH-1000XM4 ist die Passform ebenfalls unproblematisch, nur minimal weniger luftig um große Ohren herum.

Mit großen Köpfen kommen beide Modelle zurecht. Auch bei Hutgröße 64 / 3XL sitzt keiner der beiden am mechanischen Limit.

Für den Transport sind beide Modelle praktisch ähnlich: Beide Kopfhörer sind faltbar und werden mit einem kompakten Reise-Case ausgeliefert.

Gemeinsamkeiten

Beide Geräte verhalten sich in den für diesen Zweck relevanten Punkten ähnlich:

  • Passive Abdichtung: Beide Kopfhörer umschließen das Ohr und dämpfen Umgebungsgeräusche schon rein mechanisch deutlich ab.
  • ANC-Qualität: Die aktive Geräuschunterdrückung funktioniert bei beiden Modellen solide. Für den Zweck „Ruhe beim Arbeiten“ reicht das bei beiden aus.
  • Anschlüsse: Beide laden über USB-C.

Die Akkulaufzeit im reinen Standby-ANC-Betrieb habe ich noch nicht im direkten Vergleich getestet.

Fazit

Für den nüchternen Einsatzzweck – aufsetzen, ANC an, konzentriert arbeiten – sind beide brauchbar. Der Unterschied liegt weniger in „besser oder schlechter“, sondern eher in Bediengefühl, Passform und kleinen Hardware-Details.

28. Mai 2026

Inhaltsverzeichnis

Die Gliederung ist thematisch gebaut. Erst einen Abschnitt wählen, dann erscheinen nur die dazu passenden Artikel.

Kein Abschnitt ausgewählt0 Artikel

Bitte links einen Abschnitt auswählen.

28. Mai 2026

Q&A Profunktoren als Effektgeräte

Q

Frage: Profunktor war noch mal was genau? Kovariant und kontravariant habe ich verstanden.

A

Antwort: Ein Profunktor ist ein Typkonstruktor mit zwei Typparametern, der im ersten Parameter kontravariant (konsumierend) und im zweiten Parameter kovariant (produzierend) ist.

Da du Kovarianz (map für Outputs) und Kontravarianz (contramap für Inputs) bereits verstanden hast, ist der Profunktor schlicht die logische Zusammenführung beider Konzepte in einer einzigen Struktur.

Die Kernidee

Stell dir einen Profunktor P[A, B] als einen Prozess, einen Datenkanal oder einen Adapter vor:

  • Er nimmt Werte vom Typ A entgegen (Input ➔ kontravariant).
  • Er liefert Werte vom Typ B zurück (Output ➔ kovariant).

Das absolut klassischste Beispiel für einen Profunktor ist eine ganz normale Funktion: A ➔ B.

Die zentrale Methode: dimap

Während ein gewöhnlicher Funktor map anbietet und ein kontravarianter Funktor contramap, bringt der Profunktor die Methode dimap mit. Mit dimap kannst du in einem einzigen Schritt den Input "vorverarbeiten" und den Output "nachbearbeiten".

Konzeptuelle Signatur:

dimap(
  in:  C ➔ A,  // Vorverarbeitung für den Input (kontravariant)
  out: B ➔ D   // Nachbearbeitung für den Output (kovariant)
): P[C, D]

Konkretes Beispiel

Angenommen, du hast eine bestehende Funktion (deinen Profunktor), die einen simplen String parst und einen Integer berechnet: String ➔ Int.

Dein System verlangt jetzt aber an einer anderen Stelle eine Funktion, die ein Objekt vom Typ HtmlInput ausliest und am Ende ein Objekt vom Typ Currency liefert: HtmlInput ➔ Currency.

Anstatt die Kernlogik des Parsings neu zu schreiben, stülpst du mit dimap einfach Adapter über die Enden:

  1. Kontravariante Seite: Du übergibst eine Funktion HtmlInput ➔ String. Sie konvertiert den neuen Typ in den Typ, den deine Kernfunktion erwartet.
  2. Kovariante Seite: Du übergibst eine Funktion Int ➔ Currency. Sie nimmt das Ergebnis der Kernfunktion und wandelt es in den Typ um, den das System am Ende haben will.

Das Ergebnis dieses dimap-Aufrufs ist eine neue Pipeline der Form HtmlInput ➔ Currency, die intern weiterhin exakt deinen alten String ➔ Int Code ausführt.

Kurzzusammenfassung

  • Funktor (kovariant): Fokus auf den Output. "Ich produziere Werte, du kannst sie mit map verändern."
  • Kontravarianter Funktor: Fokus auf den Input. "Ich konsumiere Werte, du kannst sie mit contramap passend für mich machen."
  • Profunktor: Fokus auf die Brücke zwischen Input und Output. "Ich konsumiere und produziere. Passe mit dimap beide Seiten gleichzeitig an."

Q

Frage: Das klingt so kompliziert, aber wenn ein Musiker drei Effektgeräte hat und schaltet diese in einer Signal Chain vor seiner DAW in Reihe, z. B. A ➔ B ➔ C: Dann ist B(A,C) doch auch ein Profunktor, weil B ein Effektgerät davor und eins danach geschaltet hat. Jeder Musiker macht das jeden Tag. Ist es mehr als das?

A

Antwort: Dein Vergleich ist im Kern absolut treffend. Das ist der Grund, warum funktionale Programmierung oft mit Signalwegen verglichen wird.

Lass uns deine Analogie nur minimal geraderücken, damit die Begriffe exakt sitzen:

Nicht B(A,C) als Ganzes ist der anfängliche Profunktor, sondern dein mittleres Effektgerät B selbst ist der Profunktor (z. B. ein Distortion-Pedal). Es hat einen Input (Klinke rein) und einen Output (Klinke raus).

Was du als Musiker machst, wenn du A davor und C dahinter schaltest, ist exakt die Ausführung der dimap-Funktion:

  • A (Das Gerät davor): Das ist die kontravariante Anpassung. Vielleicht ein Compressor oder ein EQ, der das rohe Signal deiner Gitarre erst einmal formt, bevor es in die Distortion (B) geht. Du bereitest den Input vor.
  • C (Das Gerät danach): Das ist die kovariante Anpassung. Ein Reverb oder Delay, das den verzerrten Sound aus B nimmt und ihn für den Mix in der DAW aufbereitet. Du verarbeitest den Output nach.

Wenn du in der Programmierung dimap(A, C) auf B anwendest, baust du quasi dein Pedalboard. Das Resultat dieses Aufrufs ist die fertige Signalkette A ➔ B ➔ C. Nach außen hin verhält sich diese Kette wie ein einziges, großes Effektgerät: Vorne geht die Gitarre rein, hinten geht der fertige Sound in die DAW.

Ist es mehr als das?

Ganz direkt: Nein. In der praktischen Softwareentwicklung ist es nicht mehr als das.

Es ist einfach nur ein Design-Pattern (eine Typklasse oder ein Interface), das formalisiert: "Hier ist eine Komponente. Ich erlaube dir, systematisch einen Pre-Processor vorne und einen Post-Processor hinten dranzuhängen, um eine neue, nahtlose Pipeline zu bauen."

Dass es in Tutorials oft so hochtrabend und kompliziert klingt, liegt ausschließlich an der Kategorientheorie. Mathematiker brauchen extrem abstrakte, universelle Namen für Konzepte, die in der echten Welt völlig alltäglich sind. Ein Gitarrist steckt Kabel um, ein Software-Architekt ruft dimap auf. Die Mechanik dahinter ist exakt dieselbe.

25. Mai 2026

WebAssembly vs. Flatpak: Deployment-Alternativen für nkrunner

Ein Werkzeug ist nur dann nützlich, wenn man es unkompliziert ausführen kann. Da der nkrunner – unsere Custom UI-Engine – als hardwarenahe Codebasis entwickelt wird, umgehen wir von Haus aus die typischen Abhängigkeits-Orgien moderner Web-Frameworks. Dennoch stellt sich die Frage, wie man die Anwendung am saubersten an den Nutzer ausliefert, ohne in der Linux-Binary-Hölle zu versinken.

Zwei moderne Ansätze drängen sich für ein solches Projekt auf: Flatpak und WebAssembly (Wasm). Beide basieren auf dem Konzept der Sandbox, lösen das Problem aber auf völlig unterschiedlichen Ebenen.

1. Das Sandbox-Modell: Isolation vs. Kapselung

  • Flatpak (Der native Weg): Flatpak nutzt Linux-Kernel-Features (Namespaces, Bubblewrap), um die Anwendung vom restlichen System zu isolieren. Der Code läuft absolut nativ auf der CPU des Hosts. Will die Engine jedoch Konfigurationsdateien lesen oder ins Netzwerk funken, muss sie explizit durch sogenannte XDG-Portals greifen. Das System schützt den Nutzer, erfordert aber Konfigurationsaufwand für das Paket-Manifest.

Exkurs: Die Ursprünge von Flatpak
Flatpak entstand aus dem historischen Bedürfnis, die chronische Fragmentierung des Linux-Desktops zu überwinden. Der Hauptentwickler Alexander Larsson startete das Projekt 2015 unter dem Namen xdg-app. Das primäre Ziel war es, Desktop-Anwendungen unabhängig vom Basis-Betriebssystem und dessen Release-Zyklen auszuliefern. Maßgeblich vorangetrieben und finanziert wird Flatpak bis heute von Red Hat und dem GNOME-Projekt (unter dem Schirm von freedesktop.org). Im Gegensatz zu Canonical, die mit Snap einen stark firmenzentrierten Weg einschlugen, etablierte sich Flatpak als der von der Community bevorzugte, dezentrale Open-Source-Standard für Desktop-Sandboxing.

  • WebAssembly (Die absolute Kapselung): Hier bietet der Browser die ultimative Sandbox. Der Engine-Kern wird in Wasm-Bytecode übersetzt und komplett vom Host-Betriebssystem isoliert ausgeführt. Es gibt keinen direkten, unkontrollierten Zugriff auf das Dateisystem. Höchste Sicherheit für den Nutzer, ohne dass auch nur eine einzige Berechtigung im OS konfiguriert werden muss.

Exkurs: Wer steht hinter WebAssembly?
WebAssembly ist eine technologische Seltenheit: Ein Standard, bei dem sich die sonst konkurrierenden Tech-Giganten einig wurden. Wasm wurde 2015 angekündigt, nachdem sich Vorgängertechnologien wie Mozillas asm.js oder Googles Native Client (NaCl) als zu kompromissbehaftet herausstellten. Entwickelt wurde Wasm in einer beispiellosen Kooperation der großen Browser-Schmieden: Mozilla, Google, Microsoft und Apple. Heute wird der Standard vom W3C (World Wide Web Consortium) gepflegt. Wasm wurde explizit erfunden, um performance-kritische Anwendungen (wie 3D-Engines, Video-Editoren oder CAD-Software) mit nahezu nativer Geschwindigkeit sicher im Browser auszuführen, ohne JavaScript als rechenintensiven Flaschenhals zu nutzen.

2. Grafik und Performance

Die Engine ist darauf getrimmt, tausende Objekte parallel bei stabilen 60 FPS zu rendern. Wie schlagen sich die Zielplattformen dabei?

  • Flatpak: Liefert kompromisslose native Performance. Der nkrunner spricht hier direkt mit den lokalen Grafikkartentreibern des Hosts (OpenGL/Vulkan) und schöpft die Hardware zu 100 % aus.

  • WebAssembly: Da die Architektur unserer Engine strikt plattformunabhängig entworfen ist, lassen sich die internen Grafik-Befehle im Web-Kontext nahtlos nach WebGL2 oder WebGPU übersetzen. Dank moderner JIT-Compiler in den Browsern läuft das überraschend performant und erreicht oft 80–90 % der nativen Geschwindigkeit. Ein minimaler Overhead bleibt durch die Abstraktionsschicht des Browsers bestehen, ist für UI-Anwendungen aber in der Regel vernachlässigbar.

3. Der Cross-Platform-Hebel

  • Flatpak: Bindet das Tooling zwingend an den Linux-Desktop. Das löst das Deployment für unsere Kern-Arbeitsumgebung, lässt aber Windows- oder macOS-Nutzer komplett außen vor.

  • WebAssembly: Das ist der architektonisch eleganteste Pfad. Aus dem gleichen Quelltext purzelt eine einzige .wasm-Datei. Der nkrunner läuft damit sofort und ohne Code-Anpassungen auf Linux, Windows, macOS, Android und iOS. Der Nutzer muss nichts installieren, keine Abhängigkeiten auflösen und keinen Paketmanager bedienen – ein Klick auf eine URL genügt, und die Engine bootet im Tab.

Die Kehrseite: Wo WebAssembly schmerzt

Wenn man den nkrunner als reine Web-App ausliefert, verliert man allerdings fundamentale Eigenschaften eines klassischen Desktop-Werkzeugs. Der Verzicht auf direkten Systemzugriff ist der Preis für die grenzenlose Portabilität:

  • Dateizugriff: Man kann nicht einfach eine lokale Konfigurationsdatei aus ~/.config/nkrunner parsen oder ungefragt Projekte vom Desktop laden. Im Browser ist man auf lokale Datenbanken (IndexedDB) oder die explizite Interaktion über Datei-Dialoge angewiesen.
  • System-Integration: Es gibt keine nativen OS-Menüs, kein echtes Tray-Icon und globale System-Shortcuts des Window-Managers lassen sich nicht einfach kapern.
  • Das "Desktop-Gefühl": Soll sich die Wasm-Version wie eine vollwertige, eigenständige App anfühlen, müsste man sie wiederum in einen nativen Wrapper verpacken (z. B. als sehr leichtgewichtige Web-View-Shell), was den Deployment-Vorteil der reinen URL wieder etwas relativiert.

Fazit für den nkrunner

Für die Entwicklung von interaktiver UI-Logik sind beide Wege extrem wertvoll.

Während der Entwicklung wird die Engine weiterhin rein nativ kompiliert, um blitzschnelle Iterationszyklen und volles Debugging zu garantieren. Für das finale Deployment zeichnet sich jedoch ein hybrider Ansatz ab: Für Power-User, die den nkrunner lokal mit tiefgreifenden Dateisystem-Rechten und maximaler GPU-Leistung nutzen wollen, ist ein Flatpak die sauberste Lösung. Um die Technologie jedoch reibungslos zu demonstrieren oder plattformübergreifend bereitzustellen, ist WebAssembly unschlagbar. Die Engine-Architektur gibt diesen doppelten Weg glücklicherweise her, ohne dass wir uns technisch in eine Sackgasse manövrieren.

9. Mai 2026

Z-Fighting und Picking: Orthogonale Tiefensortierung durch ADTs

Eine Spatial UI, die im echten 3D-Raum gerendert wird, unterliegt den mathematischen Limitierungen der Grafik-Pipeline. Ein klassisches Problem bei der Konstruktion von verschachtelten 2D-Interfaces in einer 3D-Welt ist koplanare Geometrie: Ein Textfeld-Hintergrund, der darauf liegende Text und eine danebenliegende Scrollbar besitzen fast identische Z-Koordinaten im Weltraum.

Aufgrund der begrenzten Präzision des Tiefenpuffers kann die Grafikkarte nicht verlässlich entscheiden, welches Fragment vorne liegt. Das Resultat ist Z-Fighting (visuelles Flackern).

Exkurs: Warum der Tiefenpuffer ungenau wird
Der Z-Buffer (Tiefenpuffer) der Grafikkarte speichert die Entfernung jedes Pixels zur Kamera. Bei perspektivischen Projektionen verläuft diese Auflösung jedoch nicht linear. Nah an der Kamera ist die Präzision extrem hoch. Je weiter ein Objekt entfernt ist, desto weniger Bits stehen für die Tiefenunterscheidung zur Verfügung. Zwei Flächen mit winzigem Abstand (z. B. 0.001 Einheiten) werden in der Ferne für die GPU mathematisch auf denselben Wert gerundet – das Flackern beginnt.

Das eigentliche Problem: Falsche Picking-Ergebnisse

Das visuelle Flackern ist jedoch nur ein Symptom. Das gravierendere Problem betrifft die Interaktion.

Wie in einem früheren Beitrag beschrieben, nutzt die Engine einen separaten Offscreen-Pass für das "Picking". Wenn nun die Z-Sortierung instabil ist, passiert folgendes: Die unsichtbare, großflächige Hintergrund-Geometrie einer Textzeile verdeckt mathematisch den schmalen Anfasser der Scrollbar. Der Nutzer klickt optisch auf die Scrollbar, der Auslesevorgang aus dem Framebuffer liefert jedoch die ID des Textfeldes zurück. Das UI-Element wird unbedienbar.

Exkurs: Offscreen Picking
Um zu wissen, worauf der Nutzer klickt, verwendet die Engine kein mathematisches Raycasting (Schnittpunktberechnung von Linien mit 3D-Boxen). Stattdessen wird die Szene unsichtbar im Hintergrund ein zweites Mal gezeichnet. Jedes anklickbare Element (Button, Scrollbar, Textfeld) erhält dabei keine echte Textur, sondern eine einzigartige, flache Farbe (z. B. Rotwert 12, Grünwert 104). Klickt der Nutzer, liest die CPU die Farbe des Pixels unter dem Mauszeiger aus und rechnet diese Farbe wieder in die exakte ID des UI-Elements.

Warum überhaupt ein Tiefenpuffer? (Maleralgorithmus vs. Multithreading)

Die Spatial UI im Einsatz

An dieser Stelle drängt sich eine berechtigte Architektur-Frage auf: Klassische 2D-Benutzeroberflächen (wie der Browser oder Standard-Desktop-Apps) benötigen für ihre Fensterinhalte meist gar keinen Tiefenpuffer. Warum verzichten wir nicht einfach darauf und zeichnen die Elemente strikt sequenziell von hinten nach vorne?

Dieses Konzept nennt sich Maleralgorithmus (Painter's Algorithm): Zuerst wird der Hintergrund gezeichnet, dann das Formular, dann die Scrollbar, zuletzt der Text. Was später an die Grafikkarte geschickt wird, übermalt schlicht die vorherigen Pixel. Z-Fighting existiert hier nicht, da die Zeichenreihenfolge (Draw Order) die Sichtbarkeit diktiert.

Dass wir diesen Weg in der Engine verlassen müssen, hat zwei zwingende Gründe:

  1. Echtes 3D (Spatial UI): Da unsere Fenster frei im 3D-Raum schweben und die Kamera sich kippen lässt, können sich Fenster gegenseitig durchdringen. Die CPU müsste in jedem Frame alle tausenden UI-Dreiecke mathematisch nach ihrer Distanz zur Kamera sortieren. Das ist ein massiver CPU-Flaschenhals.
  2. Lock-free Multithreading: Dies ist der entscheidende Punkt. Wie in einem früheren Devlog beschrieben, generieren wir die Geometrie für hunderte Objekte echtzeitfähig durch asynchrone Worker-Threads. Alle Prozessorkerne schreiben ihre Daten gleichzeitig in einen großen, gemeinsamen Vertex-Puffer. Dadurch ist die finale Reihenfolge der Dreiecke im Speicher nicht deterministisch. Ein Thread ist vielleicht mit den Textbuchstaben schneller fertig als ein anderer Thread mit dem zugehörigen Hintergrund.

Wir können uns also schlicht nicht auf eine vorhersehbare Zeichenreihenfolge verlassen. Wir delegieren das Problem der Verdeckung komplett an die Hardware der Grafikkarte – den Z-Buffer. Dieser per-Pixel Tiefentest ermöglicht erst unsere massive Parallelisierung auf der CPU, erfordert als Vertragspreis dafür aber zwingend exakte, mathematisch eindeutige Z-Koordinaten für jedes einzelne UI-Fragment.

"Primitive Obsession" und Magic Numbers

Die pragmatische, aber architektonisch unsaubere Lösung, um diese eindeutigen Z-Koordinaten herzustellen, sind fest kodierte Offsets (Magic Numbers). Bei der Generierung der Render-Befehle werden manuelle Fließkommawerte addiert: z + 0.001 für den Hintergrund, z + 0.002 für die Scrollbar.

Das führt zu einem klassischen Architekturfehler: der Primitive Obsession.

Exkurs: Was ist Primitive Obsession?
Der Begriff stammt aus der Refactoring-Literatur. Er beschreibt den Code-Smell (Gestank), wenn komplexe Domänenkonzepte durch fundamentale Basis-Datentypen (Primitives wie int, float oder string) abgebildet werden. Aber warum "Obsession" (Besessenheit)? Weil Programmierer dazu neigen, aus reiner Bequemlichkeit geradezu zwanghaft an diesen eingebauten Standard-Typen festzuhalten. Es fühlt sich im ersten Moment nach unnötigem Overhead an, für eine simple Tiefenkoordinate extra einen neuen Datentyp zu deklarieren. Man denkt sich: "Ein float reicht doch völlig aus!" und nutzt ihn einfach überall. Man ist "besessen" davon, alles mit primitiven Basiswerkzeugen zu erschlagen, und weigert sich, der Domäne ein eigenes Vokabular zu geben. Das rächt sich, weil der Compiler dann nicht mehr bei Logikfehlern helfen kann: Ein Betrag von "50 Euro" ist fachlich kein float (50.0), sondern sollte ein Typ Money sein. Und die topologische Reihenfolge von UI-Elementen ist kein float, sondern ein Typ Layer.

Die Reihenfolge von UI-Elementen ist eine strukturelle Information, keine Fließkommazahl. Kapselt man dies in primitiven float-Werten, wird diese Regel über alle Abstraktionsschichten hinweg ungeschützt durchgereicht. Sobald neue GUI-Komponenten hinzukommen, kollidieren die Offsets unweigerlich. Eine nachträgliche Korrektur erfordert das Anpassen global verteilter Konstanten.

Die Lösung: Topologie in das Typsystem heben

Um das Problem strukturell zu lösen, wurde die Z-Tiefensortierung innerhalb von UI-Frames aus der Geometrie-Ebene entfernt und in das Typsystem der Engine verlagert.

Anstatt rohe Z-Offsets zu verwenden, ordnet das Layout-System Render-Befehle nun einem abstrakten Datentyp (ADT). Dieser definiert ein geschlossenes Vokabular der topologischen Schichten:

Exkurs: Algebraic Data Types (ADTs)
Ein ADT erlaubt es, eine exakt begrenzte, geschlossene Menge an gültigen Zuständen zu definieren. Im Gegensatz zu einem float, der unendlich viele (und oft ungültige) Werte annehmen kann, lässt ein Aufzählungstyp (Enum/Sum Type) nur die exakt definierten Ausprägungen zu. Der Compiler garantiert, dass keine anderen Werte in das System eingeschleust werden.

Das System kennt nun folgende strikte Hierarchie:

  1. Fenster-Hintergrund
  2. Formular-Hintergrund (z. B. Input-Boxen)
  3. Aktive Zustände (z. B. aktivierte Toggles)
  4. Texthintergründe (nur für den Picking-Pass)
  5. Selektions-Markierungen
  6. Text
  7. Scroll-Spuren
  8. Scroll-Anfasser
  9. Overlay-Outlines

Die Zuordnung erfolgt deklarativ im Theme-Setup. Die tatsächliche Transformation in mathematische Z-Werte passiert erst ganz am Ende der Rendering-Pipeline in einer isolierten Funktion. Dort wird die Enum-Reihenfolge mit einem ausreichend großen Epsilon-Wert multipliziert, der garantierte Tiefenabstände erzeugt.

Lokale vs. Globale Topologie: Das Problem der durchstechenden Buttons

Überlappende Fenster im 3D-Raum

Die Einführung des ADTs für die Z-Ebenen löst das Flackern innerhalb eines Fensters. Damit entsteht jedoch sofort ein Folgeproblem: Die Z-Achse ist nun doppelt belastet. Sie definiert die absolute Position des Fensters im 3D-Raum (Global Z), aber auch die gestapelte Höhe der UI-Elemente auf diesem Fenster (Local Z).

Wenn Fenster A bei Z=0.100 liegt und Fenster B kurz dahinter bei Z=0.090, überdeckt Fenster A das Fenster B korrekt. Wenn nun aber Fenster B einen Button besitzt, der durch unsere ADT-Logik einen lokalen Z-Offset von + 0.015 erhält, liegt dieser Button absolut bei Z=0.105. Die fatale Folge: Der Button des hinteren Fensters durchsticht plötzlich die Hintergrundfläche des vorderen Fensters.

Um dieses "Punch-Through"-Problem zu verhindern, nutzt die Engine einen sogenannten FrameStackCompositor. Er entkoppelt die logische Fensterreihenfolge von der physischen Raumtiefe. Die lokalen Z-Werte aus dem ADT dürfen nicht beliebig auf die Raumkoordinate addiert werden. Sie werden stattdessen in ein streng limitiertes "Z-Band" komprimiert. Der Compositor garantiert mathematisch, dass die gesamte Dicke dieses lokalen Epsilon-Bandes (vom Fenster-Hintergrund bis zur höchsten Scrollbar) stets kleiner ist als der minimal mögliche Abstand zweier Fenster im Haupt-Szenengraph. Jedes Fenster wird beim Rendern somit als in sich geschlossene, atomare Z-Scheibe (Slice) behandelt, deren interne Schichten niemals in den Raum anderer Objekte ausbrechen können.

Fazit

Durch das Heben der Tiefensortierung in einen dedizierten Typen übernimmt der Compiler die Kontrolle über die topologische Korrektheit der Benutzeroberfläche.

Visuelles Z-Fighting bei gekippter Kamera ist physikalisch ausgeschlossen. Noch wichtiger ist jedoch die Stabilisierung des Eingabe-Routings: Verdeckungen im Picking-Buffer durch fehlerhafte Fließkomma-Offsets sind strukturell unmöglich geworden. Die Interaktionsschicht kann sich darauf verlassen, dass das, was logisch vorne liegen soll, vom Rendering-System auch als vorderstes Fragment in den Puffer geschrieben wird.

8. Mai 2026

4-Bit-GGUF-Quantisierung vs. BitNet b1.58: Der Maschinenraum der KI

In der lokalen KI-Szene hält sich ein extrem hartnäckiger Irrtum: Viele glauben, ein 4-Bit-Modell rechne bei der Textgenerierung auch wirklich vollständig mit 4 Bit. Das klingt naheliegend, ist aber technisch falsch. Es verwechselt Speicherformat (wie die KI auf der Festplatte liegt) mit der Rechenarchitektur (wie der Prozessor im Moment der Texterzeugung arbeitet).

Um zu verstehen, warum klassisches GGUF (wie wir es heute massenhaft nutzen) und die neue BitNet-Architektur (b1.58) zwei völlig verschiedene Welten sind, müssen wir kurz klären, was im Kopf einer KI eigentlich passiert.

Das kleine KI-Lexikon: Wie denkt ein Sprachmodell?

Für alle, die noch nicht tief in der Materie stecken, hier ein intuitiver Blick auf die wichtigsten Begriffe, bevor wir in die Bits und Bytes abtauchen:

  • Training vs. Inferenz: Das Training ist die Schulzeit der KI. Hier ackert sie monatelang in riesigen Rechenzentren und lernt Grammatik, Fakten und Logik. Die Inferenz ist die Abschlussprüfung bei dir zu Hause: Das fertige Modell generiert Text auf Basis deines Prompts. Es lernt dabei nicht mehr dazu, es wendet nur an.
  • Die Gewichte (Weights): Das ist das gelernte "Langzeitgedächtnis". Stell sie dir wie Milliarden von Drehreglern vor, die beim Training einmal perfekt eingestellt und dann eingefroren wurden. Diese Regler sind normalerweise hochpräzise Kommazahlen (z. B. 0.8472).
  • Die Aktivierungen (Activations): Das sind die "Gedanken" im Moment der Inferenz. Wenn du "Hallo" eintippst, fließt dieses Wort als Strom von Zahlen durch die Schichten (Layers) des Modells.
  • Der KV-Cache (Das Kurzzeitgedächtnis): Damit die KI nicht bei jedem neuen generierten Wort deinen gesamten Text von vorne lesen muss, führt sie eine Art flüchtigen Notizblock. Das nennt man Key-Value-Cache.
  • Die Matrixmultiplikation: Das ist die eigentliche Schwerstarbeit. Das Modell nimmt deine Eingabe (die Aktivierung) und multipliziert sie mit seinem Wissen (den Gewichten). Stell es dir vor, als würde die KI permanent gigantische Pro- und Contra-Listen abwägen: "Wenn das vorherige Wort 'Guten' war, wie stark spricht dieser Regler dafür, dass das nächste Wort 'Morgen' lautet?"

Exkurs: Der Bandbreiten-Tod (Die Professoren-Metapher)
Warum ist lokale KI so langsam, wenn man keine teure Grafikkarte hat? Stell dir vor, der Chip in deinem Computer ist ein brillanter Mathematik-Professor. Er kann zehntausende Gleichungen pro Sekunde im Kopf lösen. Das Problem: Die Milliarden Gewichte der KI liegen im Arbeitsspeicher (RAM) – das ist das Archiv am anderen Ende des Flurs. Für jedes einzelne Wort, das die KI generiert, muss der Assistent des Professors ins Archiv rennen und Milliarden Aktenordner heranschleppen. Der Professor langweilt sich zu Tode, weil der Assistent (die Speicherbandbreite) nicht schnell genug liefert. Das Problem der lokalen KI ist kein Mathe-Problem, es ist ein Logistik-Problem.

Genau hier setzen Quantisierung und BitNet an – aber auf völlig unterschiedliche Weise.


4-Bit GGUF: Die Fließkomma-Illusion (Der Zip-Datei-Trick)

GGUF ist ein Dateiformat (ein Container), das bei lokalen KIs extrem verbreitet ist. Wenn wir ein normales Modell (wie Llama-3) auf 4-Bit quantisieren (oft erkennbar am Kürzel Q4 im Dateinamen), tun wir das fast ausschließlich, um den Stau auf dem Flur zum Archiv zu lösen.

1. 4-Bit-Werte sind nur Codes, keine nackten Zahlen Stell dir vor, du packst einen riesigen Koffer (das Modell) extrem eng zusammen, damit er durch die schmale Tür passt. Ein 4-Bit-Wert in einem GGUF-Modell ist nicht die echte Zahl, mit der gerechnet wird. Vier Bit können nur 16 verschiedene Zustände darstellen (0 bis 15). Das ist zu ungenau für die komplexe Mathematik eines neuronalen Netzes.

Exkurs: Malen nach Zahlen (Die Intuition hinter GGUF)
Wie rechnet man präzise mit nur 16 Werten? Das Prinzip entspricht genau dem "Malen nach Zahlen". Anstatt für jeden einzelnen Punkt eines Bildes einen riesigen 16-Bit-Farbcode (z. B. #FF5733) über das Datenkabel zu schicken, schickt man einmalig eine kleine Palette mit 16 Farben voraus. Danach ruft man nur noch: "Pixel eins kriegt Farbe 3, Pixel zwei Farbe 14".
Die Zahlen 0 bis 15 im GGUF-Modell sind lediglich die Nummern der Farbtöpfe. Auf der Grafikkarte liegt die "Palette" (der Skalierungsfaktor als Fließkommazahl bereit). Die Hardware schaut auf den 4-Bit-Code, greift in den richtigen Farbtopf und rechnet mit dem hochpräzisen Wert weiter.

2. Das Auspacken (Dequantisierung) in Echtzeit Sobald diese komprimierten Daten auf der rasend schnellen Grafikkarte (GPU) ankommen, wird der Koffer ausgepackt. Die Hardware nimmt den 4-Bit-Code, verrechnet ihn mit der Kommazahl des Skalierungsfaktors und bläst ihn on the fly wieder zu einer relativ präzisen Kommazahl auf.

3. Die Rechnung bleibt hochpräzise Die Gewichte waren also nur gepackt. Die "Gedanken" (Aktivierungen) und der Notizblock (KV-Cache) laufen ohnehin im klassischen Kommazahlen-Format durch das Modell.

Das Fazit für GGUF: Wenn das nächste Wort berechnet wird, multipliziert die GPU im Maschinenraum weiterhin zwei Kommazahlen miteinander (FP16 × FP16). Die 4-Bit-Quetschung rettet uns "nur" vor dem lahmen Arbeitsspeicher. Die eigentliche Mathematik bleibt klassisch schwer.


Der asketische Ninja: BitNet b1.58 (Die Architektur-Rebellion)

Während 4-Bit-GGUF ein bereits schlaues Modell nachträglich zusammenquetscht (Post-Training Quantization), setzt BitNet b1.58 ganz am Anfang an: beim Training in der Fabrik.

Die Idee lautet: "Wir zwingen die KI schon im Kindergarten dazu, komplett ohne Kommazahlen auszukommen."

Die Milliarden Gewichte dieses Modells kennen nur noch exakt drei Zustände:

+1,  0,  -1

(Positiv, Neutral, Negativ).

Woher kommt eigentlich der Name "1.58"?

Ein Schalter (1 Bit) hat 2 Zustände (An oder Aus). Zwei Schalter (2 Bit) haben 4 Zustände (00, 01, 10, 11). Die Entwickler wollten aber exakt 3 Zustände (-1, 0, 1). Ein Bit ist zu wenig, zwei Bits sind Platzverschwendung. Der Logarithmus zur Basis 2 von 3 lautet: log2(3) ≈ 1,58496. Ein Gewicht in diesem Modell trägt also eine Informationsdichte von etwa 1,58 Bit. Daher der Name b1.58.

Der Mathe-Shift: Die Multiplikation stirbt

Erinnern wir uns an die Milliarden Multiplikationen in normalen Modellen. Eine Rechnung wie 0.8472 × 0.5123 ist extrem anstrengend für den Chip. Was passiert, wenn die Gewichte nur noch +1, 0 oder -1 sind?

Aus der klassischen Rechnung:

(Gewicht_A × Gedanke_A) + (Gewicht_B × Gedanke_B)

Wird bei BitNet schlagartig Folgendes:

Gedanke_A - Gedanke_B

Exkurs: Das Postverteilzentrum (Die Intuition hinter BitNet)
Um zu begreifen, wie radikal dieser Schritt ist, stell dir das Netzwerk als riesiges Postverteilzentrum vor. Normalerweise wiegt ein Mitarbeiter jedes Paket (den "Gedanken") und multipliziert das Gewicht mit einer komplexen Portotabelle (0.8472). Das dauert ewig und braucht Taschenrechner.
BitNet feuert die Mitarbeiter mit den Taschenrechnern. Es gibt nur noch drei Laufbänder: Band 1 läuft vorwärts (+1), Band 2 läuft rückwärts (-1), Band 3 führt direkt in den Mülleimer (0). Die Pakete werden nicht mehr berechnet, sie werden nur noch unbesehen auf Bänder geworfen (Addiert, Subtrahiert oder Ignoriert).

Aus der gigantischen, stromfressenden Multiplikationsmaschine wird eine simple Additionsmaschine. Normale CPU-Prozessoren (wie in deinem Laptop) können das über spezielle Vektorbefehle (AVX2) rasend schnell ausführen.


CPO und BitNet: Wie man einen dreistufigen Schalter erzieht

Lange Zeit galt in der Szene die Annahme: „BitNet ist mathematisch faszinierend, aber man kann es nicht zu einem vernünftigen, höflichen Chatbot trainieren.“

Wenn ein normales Modell mit Techniken wie RLHF oder DPO manieren lernt – also lernt, dass eine hilfreiche Antwort besser ist als eine toxische –, werden die Gewichte minimal justiert. Zum Beispiel von 0.842 auf 0.841. Bei BitNet gibt es diese feinen Nuancen nicht. Man kann eine 1 nicht "ein bisschen" anpassen.

Der wirkliche Durchbruch gelang kürzlich durch die Kombination von BitNet b1.58 mit CPO (Contrastive Preference Optimization).

Exkurs: Die Magnet-Metapher (Die Intuition hinter CPO)
Ältere Methoden (wie RLHF) brauchten einen zweiten "Lehrer-Bot", der die Antworten der KI bewertete, ähnlich einem Lehrer, der Schulnoten vergibt. Das war teuer und komplex.
CPO arbeitet kontrastiv. Stell dir zwei Magnete vor. CPO zeigt der KI gleichzeitig eine sehr gute und eine sehr schlechte Antwort. Das Verfahren sagt der KI nicht einfach "Das hier ist Note 1". Stattdessen nutzt es die Mathematik, um die KI aktiv in Richtung der guten Antwort zu ziehen und sie gleichzeitig aktiv von der schlechten Antwort abzustoßen. Es maximiert die Differenz (den Kontrast) zwischen dem gewünschten und dem abgelehnten Verhalten, und das direkt innerhalb des Modells, ohne externen Lehrer-Bot.

Um dieses kontrastive Lernen auf die starren BitNet-Schalter anzuwenden, nutzt man einen genialen Architektur-Trick (Quantization-Aware Training):

  1. Das Schatten-Modell: Im Hintergrund der Grafikkarte liegen während des CPO-Trainings weiterhin hochpräzise Fließkomma-Zahlen.
  2. Die harte Maske: Für die Vorhersage (Forward Pass) der Antworten werden diese Schatten-Zahlen hart auf -1, 0 oder +1 gezwungen. Die KI "spricht" also im strikten 1.58-Bit-Modus.
  3. Das CPO-Update: Das CPO-Verfahren wendet den oben beschriebenen Magnet-Effekt an und schickt ein sanftes Korrektur-Signal zurück.
  4. Das Kippen des Schalters: Dieses Signal verändert die unsichtbaren Fließkomma-Zahlen im Hintergrund. Irgendwann kippt diese Hintergrund-Zahl über einen Schwellenwert (z.B. von 0.49 auf 0.51), und das harte, sichtbare BitNet-Gewicht springt schlagartig von 0 auf +1.

Diese Kombination beweist endgültig, dass die 1.58-Bit-Architektur nicht nur ein theoretisches Spielzeug ist. Sie ermöglicht steuerbare, hilfreiche Chatbots, die auf einer normalen CPU extrem schnell Text generieren und dabei drastisch weniger Strom verbrauchen.


Hardware-Praxis: Warum der AMD Ryzen 7 5700G dieses Konzept perfekt verdeutlicht

Um die Theorie greifbar zu machen, schauen wir uns ein klassisches Hardware-Beispiel an: Einen Computer mit dem AMD Ryzen 7 5700G. Dieser Prozessor ist eine sogenannte "APU" (Accelerated Processing Unit) – er vereint einen klassischen Hauptprozessor (CPU) und eine Grafikkarte (iGPU) auf einem einzigen Chip.

Genau diese Architektur zeigt uns den fundamentalen Unterschied zwischen GGUF und BitNet in Perfektion. Das Zauberwort hierbei lautet UMA Frame Buffer.

Das Speicherproblem: Teure, dedizierte Grafikkarten (wie eine Nvidia RTX) haben ihren eigenen, extrem schnellen Videospeicher (VRAM) direkt auf ihrer Platine. Die integrierte Grafikkarte des Ryzen-Chips hat das nicht. Sie muss sich den normalen Arbeitsspeicher (DDR4-RAM) deines Computers mit der CPU teilen. Das nennt man Unified Memory Architecture (UMA).

Damit die Grafikkarte überhaupt arbeiten kann, muss das System einen Bereich im Arbeitsspeicher abstecken und sagen: "Dieser Bereich gehört ab sofort exklusiv der Grafikeinheit!" – das ist der UMA Frame Buffer Size.

Szenario 1: Die GGUF-Fließkomma-Welt Wenn du ein komprimiertes 4-Bit-GGUF-Modell auf diesem Ryzen-Chip ausführst, willst du unbedingt, dass die integrierte Grafikeinheit die Arbeit übernimmt. Warum? Weil nach dem Auspacken der 4-Bit-Codes (Malen nach Zahlen) weiterhin Milliarden von schweren Fließkomma-Multiplikationen anfallen, auf die Grafikkarten spezialisiert sind. Damit das klappt, muss der UMA Frame Buffer im System groß genug eingestellt sein, damit das gesamte komprimierte Modell auf den exklusiven Parkplatz der Grafikkarte passt. Ist dieser Puffer zu klein, verweigert die Grafikkarte die Arbeit, und das Modell stottert lahm über die CPU.

Szenario 2: Der BitNet-Paradigmawechsel Hier dreht sich die Architektur der KI und damit auch die Nutzung der Hardware komplett um. Da BitNet Multiplikationen durch simple Additionen ersetzt, langweilt sich die Grafikkarte plötzlich. Schlimmer noch: Grafikkarten sind überhaupt nicht darauf ausgelegt, massenhaft reine Additionen auszuführen.

Dafür springen jetzt die starken, "normalen" CPU-Kerne des Ryzen 5700G ein! CPUs lieben simple Additionen und können sie über Vektorbefehle blitzschnell abarbeiten. Das Geniale daran: Die CPU braucht keinen exklusiv abgetrennten UMA Frame Buffer. Sie hat sowieso Zugriff auf den gesamten Arbeitsspeicher.

Die künstliche Grenze zwischen CPU-RAM und iGPU-RAM verschwindet für die KI. BitNet macht den klassischen Hauptprozessor wieder zum Star und löst damit Hardware-Probleme, an denen herkömmliche KI-Modelle kläglich scheitern würden.


Zusammenfassung: Der wahre Unterschied

"GGUF vs. BitNet" ist streng genommen kein Entweder-Oder. GGUF ist der Koffer, BitNet ist die Maschine im Koffer. Es wird in Zukunft BitNet-Modelle geben, die bequem als .gguf Datei auf deinen Rechner geladen werden.

Der wirkliche Unterschied lässt sich in einem Satz zusammenfassen: Der Unterschied zwischen einem Transportproblem und einem Mathematikproblem.

  • 4-Bit-GGUF löst ein Transportproblem: Es packt die riesigen Datenmengen wie in eine Zip-Datei, damit sie schnell vom lahmen Arbeitsspeicher in den Prozessor rutschen. Dort angekommen werden sie wieder entpackt, und der Chip rechnet mit der gewohnten, hochkomplexen Fließkomma-Mathematik weiter. Das Modell "denkt" also nicht in 4 Bit – es "reist" nur in 4 Bit.
  • BitNet b1.58 löst ein Mathematikproblem: Es wirft die schwere Kommazahlen-Multiplikation komplett aus dem Fenster. Indem die Gewichte strikt auf -1, 0 und 1 beschränkt werden, ersetzt das Modell komplexe Mathe-Aufgaben durch simples, blitzschnelles Addieren und Subtrahieren.

BitNet ist also kein weiteres Komprimierungsformat für die Festplatte, sondern ein völlig neuer Motor für den Prozessor. Und genau diese clevere Vereinfachung der Mathematik ist die echte Revolution, die lokale KI in naher Zukunft extrem schnell, akkuschonend und auf fast jedem Alltagsgerät möglich machen wird.

7. Mai 2026

Devlog: Ctrl-P als ruhiger Einstieg in die Kommandosuche

Heute ging es um eine kleine, aber recht grundlegende Stelle im Editor: Kommandos sollen nicht nur irgendwo existieren, sondern im Arbeitsfluss auffindbar sein. Nicht als großes Einstellungsfenster, nicht als Dokumentationsersatz, sondern als ruhige Übersicht direkt im HUD.

Der Einstieg dafür ist Ctrl-P. Die Taste öffnet den HUD-Editor, und derselbe Text dient jetzt zusätzlich als Suchstring für eine Command-Palette in der Bildschirmmitte.

HUD-Command-Palette

Der konkrete Schritt: Beim Öffnen des HUD-Editors erscheint zusätzlich eine zentrierte Command-Palette. Während man in die Ctrl-P-Textbox tippt, wird die Tabelle gefiltert. Sichtbar sind Kommandoname, Tastenkürzel und eine kurze Beschreibung.

Das klingt zunächst unspektakulär. Genau das ist hier auch beabsichtigt. Es soll kein neues großes Bedienkonzept sein, sondern eine einfache Klärung: Welche Aktionen gibt es gerade, wie heißen sie, wie löse ich sie aus?

Warum das überhaupt nötig ist

Bei einem grafischen Editor wachsen Kommandos oft schleichend. Erst gibt es ein paar Tastenkürzel. Dann ein Kontextmenü. Dann Sonderfälle für Debug-Ansichten, Selektion, Textmodus, Viewports, Hilfsanzeigen. Irgendwann ist das System für den Entwickler noch logisch, für den späteren Benutzer aber nicht mehr unmittelbar sichtbar.

Ctrl-P ist dafür ein guter Ort. Es ist bereits ein temporärer HUD-Einstieg: aufrufen, etwas eingeben, wieder schließen. Die Command-Palette hängt sich an genau diese Bewegung an, statt eine zusätzliche Oberfläche zu erzwingen.

Die Palette ist ein Gegenmittel gegen verstreute Bedienlogik. Sie nimmt vorhandene Kommandos und macht sie als Liste sichtbar. Wichtig ist dabei nicht nur die Anzeige selbst, sondern die Richtung im Code: Kommandos sollen stärker als Daten beschrieben werden. Ein Kommando ist dann nicht nur ein Zweig in irgendeiner Eingabelogik, sondern ein kleiner beschreibbarer Eintrag mit Name, Auslöser und Zweck.

Das ist kein spektakulärer Umbau. Eher ein Aufräumen an einer Stelle, die später sonst teuer wird.

Was sichtbar geändert wurde

Die sichtbare Änderung ist die Tabelle in der Bildschirmmitte. Sie bleibt bewusst schlicht:

  • links der Kommandoname,
  • daneben bekannte Tastenkürzel,
  • rechts eine knappe Beschreibung.

Die Suche ist als Volltextsuche gedacht. Man muss also nicht wissen, ob etwas als Menübefehl, Tastenkürzel oder interne Aktion geführt wird. Ein Begriff reicht, und die Liste schrumpft auf die passenden Einträge.

Das Schließen folgt dem bestehenden Verhalten: Escape beendet den Modus, ebenso erneutes Ctrl-P. Damit bleiben HUD-Textbox und Command-Palette temporäre Werkzeuge und werden kein dauerhaftes Panel, das Platz beansprucht.

Was absichtlich nicht gezeigt wird

Der Screenshot zeigt nur das Ergebnis im UI. Die interessantere Arbeit liegt darunter, aber sie muss nicht öffentlich ausgebreitet werden. Es geht allgemein um weniger Verzweigung, weniger doppelte Beschreibungen und mehr kleine Datentypen, die das Verhalten beschreiben.

Das ist eine nüchterne Architekturarbeit. Keine große neue Engine-Funktion, kein Demo-Effekt. Eher eine Maßnahme gegen künftige Unordnung.

Mir ist dabei wichtig, dass solche Änderungen nicht zu breit werden. Ein kleiner Cluster ist besser als ein halber Umbau. Wenn Eingabe, Menüs, Editorzustand und Rendering gleichzeitig angefasst werden, ist nachher schwer zu sagen, welche Änderung welches Verhalten verursacht hat. Deshalb hier nur ein enger Schnitt: Command-Beschreibung, Filtermodell, HUD-Anzeige.

Warum das zur Richtung des Projekts passt

Das Projekt bewegt sich seit einiger Zeit weg von einzelnen Speziallösungen hin zu beschreibbaren Strukturen. Nicht alles muss sofort eine große DSL werden. Aber Formulare, HUD-Elemente, Kommandos und Zustände sollten so gebaut sein, dass man sie lesen kann, ohne erst zehn Callchains im Kopf zu simulieren.

Eine Command-Palette ist dafür ein guter Prüfstein. Wenn ein Kommando nur durch implizite Logik existiert, lässt es sich schlecht anzeigen. Wenn es als Datenbeschreibung existiert, kann man es filtern, sortieren, dokumentieren oder später anders darstellen.

Ctrl-P wird damit nicht zu einem magischen Sonderfall, sondern zu einem Einstiegspunkt in ein allgemeineres Modell: Text rein, passende Kommandos sichtbar machen, Aktion finden, Modus wieder verlassen.

Das ist der eigentliche Nutzen: Die Anzeige zwingt zu etwas mehr Ordnung.

Stand

Der aktuelle Stand ist bewusst pragmatisch. Die Palette ist da, die Suche funktioniert, und vorhandene Kommandos werden zusammengeführt. Noch ist das kein endgültiges Command-System für alle Eingabearten. Es ist eher ein Zwischenstand, der die Richtung vorgibt.

Der nächste sinnvolle Schritt wäre nicht, sofort mehr Oberfläche zu bauen. Besser wäre, weitere verstreute Kommandobeschreibungen nach und nach in dasselbe Modell zu ziehen. Langsam, testbar, ohne den Rest des Editors dabei unnötig aufzureißen.

Für heute reicht das: Ctrl-P, ein Suchfeld, eine Tabelle, weniger Rätselraten.

5. Mai 2026

Kovarianz und Kontravarianz

Kovarianz und Kontravarianz leicht erklärt: Producer vs. Consumer

Wer sich tiefer mit statisch typisierten Sprachen (wie Java, C#, TypeScript oder Scala) und Generics beschäftigt, stößt unweigerlich auf zwei Begriffe: Kovarianz und Kontravarianz (engl. Covariance und Contravariance).

Dahinter verbirgt sich eine sehr einfache und klare Regel, wie Typen sich zueinander verhalten, wenn sie Daten produzieren oder konsumieren.

Schauen wir uns das Ganze an einem klassischen Beispiel an: Hunde und Tiere.


Die Basis: Subtyping (Vererbung)

Beginnen wir mit einer simplen Tatsache der Objektorientierung: Ein Hund ist ein Tier. Er erbt von Tier. In der Typenlehre schreibt man das so:

Dog <: Animal

(Lesehilfe: Dog ist ein Subtyp von Animal)

Überall dort, wo im Code ein Animal verlangt wird, können wir problemlos einen Dog übergeben. Aber was passiert, wenn wir Generics oder Container wie Listen, Producer oder Consumer ins Spiel bringen?


Kovarianz: Der Producer (Lesen)

Ein Producer ist ein Datentyp, der Objekte ausgibt oder liefert (z. B. eine Liste, aus der wir nur lesen, oder eine Factory-Klasse).

Die Regel: Bei Producern bleibt die Vererbungsrichtung gleich. Sie verhalten sich kovariant (gleichsinnig).

         Dog  <:          Animal
Producer[Dog] <: Producer[Animal]

Warum ist das so?
Stell dir vor, du hast eine Funktion, die einen Producer[Animal] verlangt. Die Funktion erwartet also irgendetwas, das ihr Tiere liefert. Wenn du ihr nun stattdessen einen Producer[Dog] (z.B. eine Hundezucht) übergibst, ist das völlig in Ordnung! Alles, was der Producer[Dog] liefert, sind Hunde – und da jeder Hund auch ein Tier ist, wird die Erwartung der Funktion perfekt erfüllt.


Kontravarianz: Der Consumer (Schreiben)

Ein Consumer ist ein Datentyp, der Objekte entgegennimmt oder verarbeitet (z. B. ein Event-Listener oder ein Datenbankschreiber).

Die Regel: Bei Consumern dreht sich die Vererbungsrichtung um. Sie verhalten sich kontravariant (gegensinnig).

         Dog  <:          Animal
Consumer[Dog] >: Consumer[Animal]

(Lesehilfe: Ein Consumer[Dog] ist ein Supertyp, also: allgemeiner von/als Consumer[Animal]. Überall dort, wo ein Consumer[Dog] verlangt wird, kann also ein Consumer[Animal] einspringen.)

Consumer[Dog] ist der schwächere, also allgemeinere Vertrag.

Consumer[Animal] ist der stärkere, speziellere Vertrag. Er muss mit allen verschiedenen Animal Subtypen klarkomen, deshalb sind die Anforderungen an diesen größer. Also ist seine Ausprägung anspruchsvoller, und in diesem Sinne ist diese Klasse dann spezieller.

Warum ist das so?
Der Name kontravariant verrät es bereits: Die Vererbungsbeziehung verläuft hier exakt in die entgegengesetzte Richtung. Stell dir vor, eine API verlangt einen Consumer[Dog] – also jemanden, der einen Hund entgegennimmt und sich mit ihm beschäftigt (z. B. ihn füttert oder pflegt). Wenn du nun einen Consumer[Animal] (z. B. eine allgemeine Tierpflege-Station) übergibst, ist das völlig sicher und korrekt. Eine Tierpflege-Station weiß, wie man jedes beliebige Tier behandelt. Wenn wir ihr also einen Hund übergeben, kommt sie damit spielend zurecht.

Wer jemanden braucht, der sich um Hunde kümmert, kann problemlos eine allgemeine "Tier"-Pflegestation nutzen, denn diese kann ganz selbstverständlich auch mit Hunden umgehen.

Zusammenfassung

Kovarianz:
Ich darf einen spezielleren Lieferanten benutzen.

Kontravarianz:
Ich darf einen allgemeineren Empfänger benutzen.

Ein Blick über den Tellerrand: Was ist, wenn wir auf OOP verzichten?

Spielen Kovarianz und Kontravarianz überhaupt eine Rolle, wenn man auf Objektorientierte Programmierung (OOP) ganz verzichtet?

Ja, absolut. Kovarianz und Kontravarianz spielen auch dann eine zentrale Rolle.

Diese Konzepte (zusammenfassend als "Varianz" bezeichnet) sind keine Erfindungen der OOP. Sie stammen ursprünglich aus der Typtheorie und der Kategorientheorie. Sie sind in jedem statischen Typsystem relevant, das Untertypen (Subtyping) oder parametrische Polymorphie (Generics) unterstützt – völlig unabhängig vom gewählten Programmierparadigma.

Hier sind die wichtigsten Bereiche außerhalb der OOP, in denen Varianz unverzichtbar ist:

1. Funktionstypen (Higher-Order Functions)

Das fundamentalste Beispiel für Varianz findet sich in der funktionalen Programmierung beim Übergeben von Funktionen (Callbacks). Damit ein Typsystem sicherstellen kann, dass eine übergebene Funktion zur Laufzeit typsicher arbeitet, wendet es eine feste Regel für das Subtyping von Funktionen an:

  • Funktionen sind in ihren Parametertypen (Eingabe) kontravariant.
  • Funktionen sind in ihren Rückgabetypen (Ausgabe) kovariant.

Ein anschauliches Beispiel: Wenn eine Funktion als Parameter einen Callback vom Typ (Tier) -> Hund erwartet (nimmt ein Tier, gibt einen Hund zurück), ist es sicher, stattdessen eine Funktion vom Typ (Lebewesen) -> Pudel zu übergeben. Die Eingabe darf allgemeiner sein (Kontravarianz: Lebewesen ist der Supertyp von Tier), während die Ausgabe spezifischer sein darf (Kovarianz: Pudel ist ein Subtyp von Hund).

2. Funktionale Programmierung (Typklassen)

In stark typisierten, rein funktionalen Sprachen wie Haskell existiert keine Vererbung im OOP-Sinne. Stattdessen wird Varianz explizit durch Typklassen gemacht, die direkt auf kategorientheoretischen Prinzipien basieren:

  • Kovarianz (Functor): Ein Datentyp wie eine Liste ist ein Funktor. Man kann eine Transformation (z. B. via map) auf die Struktur anwenden, wodurch aus einem List[A] ein List[B] wird, ohne die innere Struktur aufzubrechen.
  • Kontravarianz (Contravariant): Dies tritt bei Typen auf, die Werte "konsumieren" statt sie zu produzieren, wie beispielsweise Prädikate (Filterbedingungen) oder Sortier-Comparatoren.
  • Profunktoren (Profunctor): Strukturen, die sowohl kontravariante als auch kovariante Parameter besitzen, wie eben Funktionstypen, die etwas annehmen und etwas anderes zurückgeben.

3. Strukturelles Subtyping

In Sprachen mit strukturellen Typsystemen (z. B. TypeScript oder OCaml), wenn diese rein datengetrieben ohne Klassen genutzt werden, wird die Typ-Kompatibilität durch die Form der Daten (Records, Interfaces) bestimmt. Sobald du verschachtelte Typ-Aliase oder Unions zuweist, rechnet der Compiler im Hintergrund permanent mit den Varianz-Regeln, um zu entscheiden, ob Datensatz A typsicher anstelle von Datensatz B verwendet werden darf.

Das Fazit:
OOP macht Varianz für viele Entwickler lediglich sichtbarer, da sie eng mit expliziten Vererbungshierarchien (z. B. class Hund extends Tier) und Sprachfeatures wie <? extends T> in Java oder in/out in Kotlin und C# verwoben wird. Das zugrunde liegende Prinzip – die Gewährleistung der Typsicherheit beim Zusammensetzen komplexer Daten- und Funktionstypen – ist jedoch ein universelles, mathematisches Konzept der gesamten Informatik.

4. Mai 2026

Theme-Konfiguration und Architektur-Updates

In den vergangenen Tagen lag der Fokus auf der Flexibilisierung der Benutzeroberfläche und der internen Datenverarbeitung.

Aktueller Stand der UIAbb 1: Die Spatial UI.

Auslagerung der Theme-Konfiguration

Bisher waren viele farbliche Anpassungen der Benutzeroberfläche fest im Quelltext der Engine verankert. Um das System flexibler zu machen, wurde das Theming (Light/Dark Mode) nun vollständig in die Laufzeitkonfiguration ausgelagert.

Die Farbpaletten werden beim Start aus einer Konfigurationsdatei eingelesen. Zusätzlich wurde eine Automatisierung integriert, die basierend auf der lokalen Systemzeit selbstständig zwischen Tag- und Nachtmodus wechselt. Um den aktuellen Zustand (etwa nach einem manuellen Eingriff des Nutzers) über Neustarts hinweg zu erhalten, schreibt die Engine diese Statusänderungen autonom in eine flüchtige, lokale Einstellungsdatei.

Zusammenfassung aktueller Updates

Neben der UI-Konfiguration wurden in letzter Zeit mehrere strukturelle Erweiterungen an der Engine vorgenommen:

  • Text-Parsing und Ausführungspläne: Es wurde ein lokaler Workflow zur Verarbeitung strukturierter Textdaten (etwa aus LLM-Antworten) implementiert. Ein Parser extrahiert Code-Blöcke aus Rohtexten und erstellt daraus einen isolierten Ausführungsplan. Bevor Dateien lokal geändert werden, bietet das System eine sichere Vorschau (Dry-Run).
  • Lokales Bild-Caching (SQLite): Die Einbindung asynchroner Bildquellen (wie im Webcam-Test) wurde um eine lokale Datenbank-Ebene erweitert. Bilddaten werden im Hintergrund gecacht. Das reduziert redundante Netzwerkanfragen, sichert die Anzeige bei Verbindungsabbrüchen und ermöglicht die Wiedergabe einer lokalen Historie (Time-Lapse).
  • Zustandsverwaltung (Reducers): Die Verarbeitung von Nutzereingaben und UI-Events wurde architektonisch umgebaut. Das System nutzt nun ein strengeres Immutable-State-/Reducer-Pattern, bei dem Eingaben von zustandsfreien Logik-Blöcken verarbeitet werden. Diese generieren saubere, lineare Befehlsketten (Commands), was die Stabilität der UI und die Zuverlässigkeit der Undo/Redo-Historie deutlich erhöht.
  • Räumliche Code-Visualisierung: Ein neues Tooling erlaubt es, Quelltext-Dateien automatisiert auszulesen und als geordnetes Raster von Text-Kacheln im 3D-Raum darzustellen. Dies erleichtert die Navigation und den visuellen Überblick in wachsenden Codebasen.

Die schrittweise Trennung von hartkodierter Logik und konfigurierbaren Datenströmen stabilisiert die Engine als eigenständiges Werkzeug.