Alt-F4 #61 - Draftsman: Ein Python-Modul um Blaupausen zu erstellen 27.05.2022
übersetzt von EDLEXUS
Für die dieswöchige Ausgabe von ALT-F4 besinnen wir uns auf unsere Wurzeln als FFF-Nachfolger im Geiste zurück und vertiefen uns in ein techisches Nischenthema. redruin1 präsentiert seine neueste Erfindung: Factorio Draftsman. Natürlich gab es bereits andere Projekte, welche versuchten eine Bibliothek für Factorio-Blaupausen-Generation zu bilden, aber Draftsman versucht, der neue Standart zu werden. Motivation, technische Details und einige spaßige Projekte, all das und vieles mehr in dieser Ausgabe von ALT-F4!
Draftsman redruin1
Vor einigen Monaten entschied ich mich dazu, mich an einer selbst-expandierenden Fabrik zu versuchen. Ich wurde von einigen beeindruckenden Beispielen inspiriert. Ich hatte bereits einige grundlegenden Ideen für die Logik und wie die Fabrik sich selbst überwachen sollte, und natürlich auch einige große Ideen für Dinge, die die Fabrik selbstständik können würde. Das einzige Problem war, das ich bisher noch nie Kombinatoren verwendet habe und sie eigentlich für die Entscheidungsfindung vorgesah.
Das ist aber kein Problem, wir wechseln einfach auf einer Test-Welt in den Editor und probieren einige Sachen aus!
Ich bin vielleicht etwas vom Fokus abgekommen.
Hier ist meine CPU. Sie stellt die siebte Version dar (glaub ich). Sie besitzt ROM, RAM, einen Stack, 256 Register, über 40 Befehle, Breakpoints und Schrittweise Codeexekution, Hardware und Software-Interrupts und ein generisches Schaltkreis-Interface, um mit anderen Maschinen zu kommunizieren.
Ironischerweise soll es aber gar nicht über irgendwas davon gehen. Das ist alles nur Teil der Vorgeschichte.
Ich habe die zweite Version des Computers begonnen und wollte kompakteren ROM. Ich kam auf das unten gezeigte Design, welches 4KiB an echten 32-Bit Nummern pro Zeile speichern kann:
Der ROM ist sehr dicht, aber er funktioniert mit einem System, bei dem jeder Wert in zwei 16-Bit Nummern getrennt wird, welche einzeln gespeichert werden und bei der Ausgabe wieder kombiniert werden. ROM’s sind in der Regel sehr aufwändig herzustellen, da jeder Wert in jedem Kombinator von Hand eingestellt werden muss. An diesem Punkt ist mir mein schön Kompaktes System auf die Füße gefallen, da ich jetzt zusätzlich jeden Wert teilen, Bitweise-UND-Verknüpfen und verschieben muss und jeweils zwei Werte an bestimmten Stellen eintragen muss, mit dem korrekten Wert und Signaltyp. So war es schmerzhaft auffällig, das es eine unglaubliche Aufgabe wäre, dutzende, oder sogar hunderte oder tausende Werte einzutragen, um das gesamte System auszunutzen.
Die Lösung? Einen Computer diese Arbeit für mich machen lassen. Er kann dies viel schneller und besser als, ohne dabei Flüchtigkeitsfehler zu machen. Factorio’s Blaupausen-Stringimport-Funktion kann jeden korrekt formatierten String verwenden. Meine Aufgabe war es jetzt nur noch, diesen Textstring korrekt mit meinen gewünschten Kombinatoreinstellungen zu erstellen.
Dieses Konzept ist prinzipiell nichts neues. Selbst eine einfache Suche aus Interesse bringt bereits mehrere Ergebnisse: factorio-blueprint
NPM module von demipixel, justarandomgeek’s Compiler für seinen gigantischen Kombinator-Computer, eine generische Kombinator-Befehlssprache von Jobarion, Bild-zu-Blaupause-Konverter, etc. Die Liste ist lang.
Mit all diesen Beispielen hoffte ich, dass ich einige Übereinstimmungen mit einem dieser Systeme finden würde, die ich als Ausgangspunkt für meine Lösung verwenden könnte, ohne die selben Probleme nocheimal zu lösen. Alle diese Lösungen hatten aber eins gemeinsam: Sie hatten alle Probleme!
- Viele Implementierungen waren sehr spezifisch nur für ihren ursprünglichen Anwendungsfall gemacht; ein Kombinator-Compiler-Script war nicht verwendbar für Anwendungen, welche nicht das Compilieren für einen speziellen Kombinator-Computer waren.
- Es fehlte eine einheitliche Sprache; viele waren in Lua, einige in Python, eins in JavaScript, eins in C++ geschrieben. Das bedeutet, dass jedes Programm seine eigene Implementierung für gemeinsame Funktionen benötigte, anstatt das einfach einer eine Funktion schreibt und andere sie übernehmen.
- Viele waren für mittlerweile stark veraltete Factorio-Versionen.
- Dokumentation für viele dieser Module war rar, was viele Nutzer wie mich davon abhält, sie zu verwenden, da nicht offensichtlich ist, was sie können und was nicht.
Ich war mit der Gesamtsituation unzufrieden und musste so in die Fußstapfen derer, die vor mir gekommen sind, folgen und meine eigene Implementierung schreiben. Was ein Spaß!
Ich habe innerhalb eines Nachmittags ein Skript geschrieben, welches perfekt funktionierte und genau das tat, was es sollte. Ich habe ein Schablonensystem genutzt und konnte das ganze so innerhalb von einer Woche komplett fertigstellen.
Aber dann habe ich mich gewundert. Es wäre nicht so schwer, ein Modul wie factorio-blueprint
für modernes Factorio aufzubereiten, und ich wette, ich kann mir irgendein automatisches System ausdenken, um automatisch Daten aus Factorio auszulesen, so dass ich nicht per Hand Quelldateien in Abhängigkeit von der Version veränderm müsste. Dann dachte ich mir, wo ich doch gerade dabei bin, könnte ich Dokumentation für den komplexen und wenig dokumentierten control_behavior
-Schlüssel in Entitäten schreiben, oder eigene Entitätentypen hinzufügen, um Gruppen von Entitäten zu bilden und zu verändern oder sogar Mod-Support hinzuzufügen. Das ist nun drei oder vier Monate her.
Nuja, hier ist ein Pythonmodul, was ich geschrieben habe.
Ich stelle vor: factorio-draftsman
Draftsman ist ein Python-Modul, um alle Arten von Factorio-Blaupausenstrings zu erstellen, verändern, modifizieren oder zu ändern. Das Paket erlaubt dir, Blaupausen mit Programmen zu erstellen und zu designen, um dich bei komplexen und sich oft wiederholenden Blaupausen, welche praktisch nicht von Hand erstellt werden können, zu unterstützen. Draftsman versucht alle Schwächen von bisherigen Werkzeugen zu lösen:
- Draftsman kann es alles. Alle Entitätstypen werden unterstützt, von Teilern bis zu Stapelgreifern. Wenn es im Spiel geht, geht es auch in Draftsman; so das du dich wieder auf dein eigentliches Problem konzentrieren kannst.
- Draftsman ist sprachübergreifend. Geschrieben in Python macht es sich sehr einfach zum installieren, einfach zu verwenden und gibt dem Benutzer Zugriff auf den gesamten Packaging-Index von Python. Du kannst wahrscheinlich alles in Python mit Draftsman machen, egal was für ein Factorio-Ding du eigentlich tust.
- Draftsman ist einfach zu verwenden. Da es von Anfang an für ein einfaches und selbst-dokumentierendes Design ausgelegt wurde, erlaubt es dir, Blaupausen und Entitäten mit selbstvervollständigbaren Methoden und Attributen zu manipulieren.
- Draftsman ist gut dokumentiert. Jede Funktion, Methode, Attribut und Klasse ist dokumentiert und auf seiner readthedocs-Seite verlinkt. Zusätzlich werden Tutorials und zusätzliches Material bereitgestellt, sowie eine große Menge an Beispielprogrammen, um dabei zu helfen, ein Verständnis für die Funktionsweise von Draftsman herzustellen.
- Draftsman ist stabil. Eine Gruppe rigoroser Tests garantiert, das Draftsman vorhersagbar und korrekt (oder zumindest korrekt genug) funktioniert. Die Tests decken 100% des Codes ab. Draftsman ist auf den aktuellsten Versionen von Python 2 und 3 verifiziert, und belegbar kompatibel mit allen Factorioversionen ab 1.0.
- Draftsman beschreibt Probleme. Draftsman besitzt “Factorio-safety” als eine zentrale Philosophie, was bedeutet, das jede Änderung an einer Blaupause, welche zu einem Fehler beim Import führen würde, einen Fehler generiert. Draftsman versucht auch “Factorio-Correctness” zu prüfen, was bedeutet, das Werte, die keinen Fehler verursachen würden, aber nicht sinnvoll sind, eine Warnung generieren. Sowohl Fehler als auch Warnungen sind mit ausgiebigen BEschreibungen versehen, so das alle Probleme mit deinem Skript in Sekunden erkannt und verstanden werden können.
-
Draftsman ist nah am Quellmaterial. Draftsman basiert alle seine Daten auf Wube’s
factorio-data
repository, was bedeutet, das außnahmslos alle Entitäten genau so sind, wie im Spiel zu erwarten. Das macht Draftsman Up-to-date, vereinfacht das updaten auf neue Factorio-Versionen ungemein und eraubt Versionskontrolle zwischen Draftsman und Factorio, falls in Zukunft Fehler auftreten sollten. - Draftsman sunterstützt Mods. Draftsman emuliert Factorio’s Data-Lifecycle direkt, was bedeutet, dass der selbe Ladeprozess, wie wenn du das Spiel startest, in einer einzigen Funktion nachgemacht wird. Zusätzlich dazu, das sichergestellt wird, das Draftsman absolut akkurat zu Factorio ist, wird es so auch kompatibel zu Mod-Prototypen, auf die direkt im Skript zugegriffen werden kann, so als währen sie Factorio-eigene Entitäten.
Draftsman besitzt besondere Klassen für jede Entität und Prototyp, und alles ist darum designt, möglichst so problemfrei wie möglich mit Blaupausenstrings und anderer Software zusammenzuarbeten. Du kannst einen Blaupausenstring von Factorio importieren und er wird automatisch in einen Draftsman-Blueprint
-Objekt umgewandelt, mit alles seinen Funktionen. Dann kannst du deine gewünschten Änderungen vornehmen und dann dieses Blueprint
-Objekt zurück in einen importierbaren Blaupausenstring umwandeln. Alternativ kannst du auch einen völlig neuen Blueprint
erstellen; Draftsman soll für dich arbeiten, nicht andersherum.
Draftsman unterstützt auch eigene "EntityLike"
-Objekte, wie beispielsweise Group
, welche dir erlauben, eigene Konstruktionen zu erstellen, welche dann zu Blaupausen hinzugefügt werden, um die Lesbarkeit und Modularität zu erhöhen. Du kannst beispielsweise ein Design für einen Schmelzenblock in einer Group
erstellen, und diese dann mehrfach in deiner Blaupause verwenden, wenn gewünscht auch gespiegelt oder rotiert.
In einem Versuch, diesen Artikel kurz zu halten, werde ich nicht bis in die kleinsten Details hineingehen, und ganz genau erklären, wie jeder Teil des Moduls funktioniert, ich habe stattdessen viel Zeit dafür aufgewendet, Dokumentation zu schreiben. Stattdessen werde ich lieber einige Dinge zeigen, die ich mit Draftsman bisher gemacht habe, sowie einige Dinge, die damit vielleicht in Zukunft angestellt werden könnten und versuche zu zeigen, warum ich dafür so viel Zeit aufgewendet habe.
Automatische Item-Stapelgrößen
Oft willst du herausfinden, wie viel Lagerplatz du für eine bestimmte Menge an Items benötigst. Allerdings basiert Lagerung in Factorio nicht auf Mengen sondern Stapeln, so dass der benötigte Lagerplatz nicht nur von der gewünschten Menge sondern auch von der Stapelgröße des gewünschten Itemtyp abhängt. Du kannst dafür eine Kombinatorschaltung errichten, um dies herauszufinden, allerdings benötigst du dort eine große Menge an Kombinatoren um die Ergebnisse zu speichern. Diese Schaltung ist langweilig zu errichten und einfach überfordert, wenn ein neues Item hinzukommt oder sich eine Stapelgröße ändert. Für so eine einfache und sich oft wiederholende Aufgabe ist ein Skript ganz klar besser geeignet:
# Schaffe ein N x 5 Gitter an verbundenen Kombinatoren für Konstanten, mit jedem Item und der jeweiligen Stapelgröße
from draftsman.blueprintable import Blueprint
from draftsman.constants import Direction
from draftsman.data import items
from draftsman.entity import ConstantCombinator
COMBINATOR_HEIGHT = 5
def main():
blueprint = Blueprint()
signals_added = 0
signal_index = 0
combinators_added = 0
x = 0
y = 0
combinator = ConstantCombinator(direction=Direction.SOUTH)
# Iterier über jedes Item in der richtigen Reihenfolge:
for item in items.raw:
# Irgnoriere verborgene Items/Entitäten
if "flags" in items.raw[item]:
if "hidden" in items.raw[item]["flags"]:
continue
# Zähle, wie viele Signale wir bereits verarbeitet haben
signals_added += 1
# Schreibe das Stapelgrößensignal
stack_size = items.raw[item]["stack_size"]
combinator.set_signal(signal_index, item, stack_size)
signal_index += 1
# Wenn wir die Anzahl an Signalen überschreiten, die ein einzelner Kombinator verarbeiten kann, wird er platziert und von vorn begonnen
if signal_index == combinator.item_slot_count:
# Füge den Kombinator der Blaupause hinzu
combinator.id = "{}_{}".format(x, y)
blueprint.entities.append(combinator)
# Setzte den Kombinator zurück
combinators_added += 1
y = combinators_added % COMBINATOR_HEIGHT
x = int(combinators_added / COMBINATOR_HEIGHT)
combinator.set_signals(None) # setzte die Signale zurück
combinator.tile_position = (x, y)
signal_index = 0
# Füge den letzten Kombinator hinzu, wenn nicht vollständig gefüllt
if len(combinator.signals) > 0:
combinator.id = "{}_{}".format(x, y)
blueprint.entities.append(combinator)
# Füge Verbindungen zu den jeweiligen Nachbarn hinzu
for cx in range(x):
for cy in range(COMBINATOR_HEIGHT):
here = "{}_{}".format(cx, cy)
right = "{}_{}".format(cx + 1, cy)
below = "{}_{}".format(cx, cy + 1)
try:
blueprint.add_circuit_connection("red", here, right)
except KeyError:
pass
try:
blueprint.add_circuit_connection("red", here, below)
except KeyError:
pass
print("Number of items added:", signal_count)
print(blueprint.to_string())
if __name__ == "__main__":
main()
Dieses Skript ist kompakt und einfach zu folgen, aber das wirklich gute an Draftsman ist, das dieses Skript dynamisch ist und anpassbar ist, egal für welche Factorio-Version. Neue Items, fehlende Items, geänderte Stapelgrößen, egal wer diese Änderungen gemacht hat, werden sie mit diesem Skript abgedeckt. Zur Illustration ist oben links der dargestellt, was das Skript in Vanilla erzeugt, oben rechts der Ausgang für eine mittelgroße Mod wie Space Exploration und unten die Ausgabe für ein Bobs + Pyanodon Mega-Modpack:
Dies trifft aber nicht nur auf Items zu. Alle Entitäten, Instrumente, Signale, Rezepte, Module und Fliesen werden im Simulierten Spielladeprozess geladen und gespeichert, um dann von Draftsman verarbeitet zu werden. Jedes Skript kann so designt werden, das es in diesen Kategorien komplett flexibel arbeitet; extra Instumente in programmierbaren Lautsprechern, neue Modultypen für nur bestimmte Maschinen, eine komplette virtuelle Signalliste, etc., alles wird von Draftsman korrekt interpretiert. Durch das interne Speichern der Modkonfiguration für später, bedeutet dies, das du die Daten nur einmal neuladen musst, immer nur wenn du die Modkonfiguration änderst.
Bild zu Blaupausen-Konverter
Das ist etwas, was ich mal aus Spaß gemacht habe. Es verwendet die Pillow
-Bibliothek um ein Bild zu laden und in eine Blaupause zu verwandeln, welche dann von der Karte aus sichtbar ist, in unter 150 Zeilen Code:
Es könnten dazu noch viele Verbersserungen gemacht werden:
- Dithering ist nur in 1x1 Tiles implementiert, da ich Probleme hatte, den Algotithmus auf größere Gebiete auszudehnen.
- Multi-Tile-Entitäten können die Fehlermetrik nicht korrekt verändern; Palettization funktioniert nur schlecht, wenn die Pixel verschiedene Größen haben.
- Einige Multi-Tile-Entitäten haben verschiedene Rotierungen. Eine bessere Implementierung würde prüfen, welche Orientierung die wenigsten Fehler produziert, anstatt nur die Standart-Orientierung zu platzieren.
- Die Farben sind hardgecodet, es wäre schön sie dynamisch aus dem Spiel zu laden, besonders bei durch Mods veränderten Kartenfarben…
Trotz dieser Probleme sieht das Ergebnis ganz gut aus, wenn man bedenkt, wie schnell es zusammengeschustert wurde. Das zeigt, das Draftsman flexibel genug ist, um komplexen Anforderungen gerecht zu werden.
Wiederauferstehung des Factorio-Movie-Players
Vor einer Weile, auf der Suche nach Beispielen für diesen Artikel, kam ich auf den Klassiker Factorio Sandstorm. Ein perfektes Projekt für mein Vorhaben; oder hätte es zumindest sein können, wenn ich die Karte im Spiel hätte öffnen können! Die originale Map-Version war mit einem antiken 0.14.20
datiert. Zusätzlich dazu wurden über die lange Zeit viele Veränderungen vorgenommen, die der Funktionalität des Skriptes, welche Bilder in Blaupausen umwandelt, im Wege standen. Auch die Karte selber hatte einige Probleme, so dass es nicht gereicht hätte, einfach eine alte Factorio-Version zu öffnen und das Skript anzuwenden. Beispielsweise nannte das build.lua
-Skript, was für das Encoding zuständig ist, automation-science-pack
und logistic-science-pack
noch science-pack-1
und science-pack-2
. Das sollte einen ungefähren Eindruck davon vermitteln können, wie alt diese Karte ist!
Es störte mich, so einen ikonischen Teil der Factorio-Geschichte verfallen zu sehen. Ich nahm mir also die Zeit um die Fehler zu beheben und das ganze auf Version 1.1.57 zu bringen:
Das Build-Script zu ändern, war problemlos per Hand möglich, aber das raw-wood
-Signal, welches die Maschine intern verwendet hat, gibt es nicht mehr in neueren Factorio-Versionen. Um dies zu beheben, habe ich jedes Vorkommen dieses Signales mit artillery-wagon
ersetzt (da ich sicher sein konnte, das es noch nicht verwendet wurde). Das Updaten der Karte erfolgte in einem Draftsman-Skript. Ich habe auch einige andere Skripte hinzugefügt, um die Bilder aus der Quelle zu extrahieren und Bildschirmfotos zu machen, welche dann automatisch zu einem Video zusammengefügt wurden, was in Python relativ einfach war. Ich habe diese Scripts verwendet, um das oben verlinkte Video zu erstellen.
Ich habe auch mit der Idee rumgespielt, Draftsman zu verwenden um eine Blaupausenbasierte Version den Bau-Skrips zu erstellen, anstatt der originalen Konsolenversion. Das würde dir ganz klar zeigen, welche SPeicherorte du mit einer drübergelegten Blaupause veränderst und würde es simpel machen, den Speicher zu erweitern (der vorhandene Speicher ist nur groß genug für 4800 Frames). Ich fand es wichtiger, das auf den neuesten Stand zu bringen, was bisher da war, insbesondere wenn ich wusste, das der vorhandene Code funktioniert. Die Informationsdichte eines Blaupausenstrings ist möglicherweise auch geringer als die eines Konsolenbefehls, welche so groß sind, das sie bei der Verwendung in Textdateien gespeichert werden. Herauszufinden, ob eine Blaupause für diesen Anwendungsfall geeignet ist, kann warten, bis ich später mal Zeit dafür finde.
Für mehr Informationen darüber, was neu ist, und auch die neue Weltdatei, verweise ich hier auf meine Fork.
Was nun?
Ich habe bereits einige Dinge mit diesem Modul gemacht, aber mein ursprüngliches Ziel war es ja, das jeder ganz einfach damit etwas machen kann. Einige Ideen, die ich machen wollte, aber bisher noch keine Zeit dazu gefunden habe, habe ich im Folgenden als Anreize/Ideengeber mal zusammengestellt:
-
Viele Kombinator-Computer-Kompiler sind als Skript geschrieben. Vielleicht könnte man ein LLVM-Äquivalent; einen generische Compiler; schaffen, dem man mitteilt, welche Befehle der Computer bearbeiten kann und der daraufhin Code einer etablierten, High-Level-Sprache, beispielsweise C, compiliert. Vielleicht könnte man sogar LLVM selbst nuten?
-
Ausnutzen von Sonderfällen für spezielle Optimierungsprobleme. Wusstest du, das man jedes Item und nicht nur Module als Angefordert in einer Entität einstellen kann? Du kannst nur Items anfordern, wenn sie errichtet wird, was den Nutzen etwas einschränkt, aber Roboter werden den Auftrag erfüllen. So ist es in einigen Fällen möglich, die Produktion in Gang zu setzten. Mit sowas wie der Recursive-Blueprints-Mod kann man, indem man Montagemaschinen mit Item-Anforderungen platziert und wieder abreißt, wenn sie ihre Items hergestellt haben, eine vollautomatische Fabrik nur mit Baurobotern errichten. Vielleicht kann so die Micro Factory weiter verbessert werden? Ein neues Ziel könnte auch sein, die geringste Entitätenzahl ohne Nutzereingabe zu erreichen, um eine Rakete zu starten.
Eine vielleicht generellere Anwendung ist diese Blaupause. Ein einzelner GEschützturm, welcher 200 panzerbrechende Munition anfordert, wenn er errichtet wird. Dies ist besonders nützlich in offensiven Aktionen in großen Beißernestern, da du schnell viele Geschütztürme verteilen kannst und sich die Roboter um die Errichtung und Versorgung mit Munition kümmern, damit du dich drauf konzentrieren kannst, dich nicht in der Beißerpampe aufzulösen.
-
Streckenfindungsprobleme. Übergebe eine Menge an Außenpostenpunkten und verwende einen Algorithmus um sie automatisch auf kürzester Strecke/mit dem wenigssten Kreuzungen/etc. zu verbinden. Vielleicht könnte man dies sogar direkt aus den Speicherständen auslesen?
-
Kombinatorschaltungen sind in der Regel sehr Komlex und für den Leien unintuitiv und schwer zu verstehen, wie ich in meiner, in der Einführung beschriebenen, ausgiebigen Probierereien herausgefunden habe. Das liegt an der Dichte der Schaltungen, den versteckten Operationen der einzelnen Kombinatoren und dem unverständlichen Haufen Kabel, der keinen Platz zum durchlaufen oder für Verständnis lässt. Es wäre schön ein Programm zu haben, dem man einen Blaupausenstring übergibt und dem Nutzer dann Labelmöglichkeiten oder ähnliches gibt, damit er eine einfach zu verstehende Dokumentation für komplexe Schaltungen schaffen kann. Ich fände es klasse, soetwas zu verwenden um vektorbasierte Schaltpläne für meinen Computer zu erstellen. Sollte ich ihn jemals fertigstellen.
-
Verwende Constraint-Satisfaction um Blaupausen zu erstellen. Ich habe damit in der Vergangenheit experimentiert, und es sollte theoretisch möglich sein, vorrausgesetzt man bekommt die Komplexität von
O(MFG)
herunter. Falls ich nochmal einen Artikel für Alt-F4 schreibe, wird er vielleicht darüber sein. -
Man kann auch neuronale Netze für dieses Ziel verwenden, es ist schließlich Python!Ich frage mich, ob man damit tatsächlich verwendbare Blaupausen erhalten kann. Vielleicht könnte man es mit den gesamten Daten aus factorio.school trainieren…
Hoffentlich hat dies den kreativen unter euch einige Ideen geliefert. Und vielleicht, aber nur vielleicht, kann jemand, der sich mit einem Skript etwas Zeit sparen möchte, etwas Zeit sparen, anstatt drei bis vier Monate darauf zu verwenden, dafür ein Python-Modul zu schreiben.
Es hat zumindest etwas Spaß gemacht. Und man hat ein oder zwei Dinge gelernt.
Nun, endlich zurück an die Arbeit.
Beitragen
Wie immer suchen wir nach Leuten, die zu Alt-F4 beitragen wollen, sei es mit einem Artikel oder durch Hilfe bei Übersetzungen. Wenn du etwas Interessantes im Kopf hast, das du mit der Community in einer eleganten Art teilen möchtest, hier kannst du das tun. Falls du dir unsicher bist, beantworten wir gerne Fragen zu Inhalt und Struktur. Falls das nach etwas klingt, woran du interessiert bist, tritt unserem Discord bei, um es nicht zu verpassen!