Seite zu Poster
Lesen Sie das Abenteuer und schreiben Sie fünf kleine Dateien, die den Ort beschreiben. Der Code in diesem Ordner prüft sie, baut ein 3D-Modell im Headless-Blender, rendert es und setzt das Poster zusammen.
Abenteuer (PDF/Text) + Richtlinien
-> brief.md Was der Text über den Ort sagt (Sie schreiben)
-> layout.json Räume, Gänge, Eingänge, in Metern (Sie schreiben; `check` validiert und zeichnet es)
-> props.py Was in jedem Raum steht (Sie schreiben; `build` modelliert es)
-> poster.json Titel, Beschriftungen, Callouts, Textbox (Sie schreiben; `poster` rendert und setzt zusammen)
-> out/poster_gm.png, poster_player.png, poster_bare.png (+ .jpg)
p2p.py befindet sich in diesem Ordner. Rufen Sie es mit dem vollständigen Pfad aus dem Arbeitsverzeichnis des Benutzers auf, damit Projektordner dort und nicht hier landen; die folgenden Befehle schreiben der Einfachheit halber python p2p.py. Verwenden Sie python3, wo python nicht Python 3 ist.
Durchgängig geltende Regeln
- Betrachten Sie jedes von Ihnen erstellte Bild. Jeder Schritt schreibt ein Bild; öffnen Sie es mit Ihrem Bildlese-Werkzeug, bevor Sie fortfahren. Die Schritte benennen die Datei. Die meisten Fehler sind im Bild offensichtlich und in den Zahlen unsichtbar.
- Meter, +x Osten, +y Norden, Boden bei z = 0. Winkel in
props.pysind Bogenmaß. - Sagen Sie, was Sie geschätzt haben. Abenteuer geben selten Größen oder genaue Positionen an. Schätzen Sie, schreiben Sie „geschätzt" in
brief.md, und listen Sie die Schätzungen auf, wenn Sie Bericht erstatten. Präsentieren Sie niemals eine erfundene Tatsache als die des Buches. - Blender läuft headless über
p2p.py. Öffnen Sie sein Fenster nicht und verwenden Sie keinen Blender-MCP-Server. - Entwürfe sind günstig. Entwurfsposter mit
--dpi 100; rendern Sie das finale mit--dpi 200, sobald der Entwurf richtig ist. - Der Projektordner enthält den Text und die Karten des Abenteuers. Halten Sie ihn aus öffentlichen Repositories heraus, es sei denn, das Abenteuer gehört Ihnen zur Veröffentlichung.
Schritt 0: Überprüfen Sie die Maschine
python p2p.py doctor
Er muss enden mit: Core pipeline: ready. Falls Python-Pakete fehlen: pip install -r requirements.txt. Falls Blender fehlt, folgen Sie docs/setup.md. Keine GPU nötig (Rendering fällt auf die CPU zurück), und ComfyUI ist optional: Übergeben Sie --comfy URL nur, wenn der Benutzer Ihnen eine gegeben hat (docs/comfyui.md).
Schritt 1: Starten Sie das Projekt und lesen Sie die Quelle
python p2p.py new PROJEKT --source abenteuer.pdf --pages 53-56
PROJEKT ist ein neuer Ordner für diese Karte, z.B. maps/der-ort-name im Arbeitsverzeichnis des Benutzers. --pages sind die eigenen Seitenzahlen des PDFs (erste Seite ist 1) für die zu kartierende Location; lassen Sie es bei einem kurzen PDF weg. Eine Text- oder Markdown-Quelle wird unverändert kopiert. Der Befehl schreibt Vorlagen für die fünf Dateien und, für ein PDF, source/page_NNN.txt und source/page_NNN.png.
Lesen Sie den gesamten Text. Dann betrachten Sie jedes Seitenbild: Karten, Diagramme und Randspalten sind nur in den Bildern. Wenn das Buch eine Karte hat, entscheidet diese Karte, wo Räume sitzen; der Text entscheidet, was darin ist.
Füllen Sie guidelines.md basierend auf dem aus, worum der Benutzer gebeten hat; alles, was er nicht erwähnt hat, behält seinen Standard. Fragen Sie den Benutzer nur, wenn Sie nicht erkennen können, welche Location kartiert werden soll.
Füllen Sie brief.md: eine Zeile pro Raum, eine pro Verbindung, eine pro Eingang. Zitieren Sie Seitennummern. Dies ist der Schritt, in dem Sie entscheiden, was gegeben und was geschätzt ist.
Größen, wenn der Text keine angibt: eine Tür ist 1 m, ein Korridor 2,5 bis 3,5 m, eine Zelle oder ein Büro 4 x 5 m, ein gewöhnlicher Raum 6 x 8 m, eine Halle 15 x 25 m, eine Höhle oder ein Hangar 30 x 50 m. Decken: 3 m gewöhnlich, 5 bis 8 m Hallen. Ein Kartenquadrat ist in Fantasy-Spielen normalerweise 5 Fuß (1,5 m); ein „Schritt" ist etwa ein Meter.
Schritt 2: layout.json
Ersetzen Sie die Vorlage mit den Räumen, Gängen und Eingängen des Ortes. docs/layout.md hat jeden Schlüssel. Zwei vollständige Projekte zum Lernen: examples/brine-chapel/ (ein Steindungeon, aus Text ohne Karte) und examples/kestrel-9/ (eine vorgefertigte Station, aus einem PDF mit einer Skizzenkarte). Das Wesentliche:
- Ein Raum ist ein achsenausgerichtetes Rechteck aus klarem Boden:
minist seine Südwestecke,maxseine Nordostecke. Lassen Sie mindestens 0,6 m (eine Wand) zwischen zwei beliebigen Räumen. - Eine Verbindung verbindet zwei Räume entlang eines Pfades von Punkten. Der erste Punkt liegt auf der Kante von Raum
a, der letzte auf der Kante von Raumb; der Pfad verlässt jeden Raum im rechten Winkel zur Wand.kindistopen,blocked(ein Einsturz versperrt ihn) odervent(ein Kanal oder Kriechgang, Raum zu Raum;zsetzt seine Höhe).doors: ["a", "b"]setzt Türen an diesen Enden.secret: truemarkiert eine Verbindung, die die Spieler nicht sehen dürfen: Ihre Türen werden zu Geheimtüren, und das Spielerposter lässt ihre Routenmarkierung weg. - Wo drei oder mehr Gänge aufeinandertreffen, benennen Sie den Ort unter
junctionsund lassen Sie die Pfade dort enden. - Ein Eingang ist ein Weg von außerhalb der Karte:
stairs,ramp,tunneloderdooran einer Wand (side:"N|S|E|W",at: Position entlang dieser Wand), oder einshaftan einem Punkt in einem Raum. Ein Gang, der die Karte verlässt und eingestürzt ist, ist eintunnelmitblocked: true. - Ein Raum, der kein Rechteck ist: Geben Sie ihm sein Begrenzungsrechteck, formen Sie es dann in
props.py(cave_fillfür Höhlen und Einstürze,partitionfür Innenwände), oder teilen Sie ihn in zwei Räume auf, die durch eine kurze breite Verbindung verbunden sind. - Ein Poster zeigt eine Ebene. Für einen Ort mit mehreren Ebenen erstellen Sie ein Projekt pro Ebene und verbinden Sie sie mit Eingängen, die als „Treppe zu Ebene 2" beschriftet sind.
Legen Sie den Ort kompakt und annähernd so tief wie breit an; das füllt ein 3:2-Blatt in der isometrischen Ansicht am besten. Setzen Sie den ersten Raum nahe (0, 0) und arbeiten Sie sich auf einem 1-m-Raster nach außen.
python p2p.py check PROJEKT
Beheben Sie jeden Fehler (jede Nachricht sagt, was zu ändern ist). Dann öffnen Sie PROJEKT/build/layout_check.png und vergleichen Sie es mit der Buchkarte oder Ihrem Briefing: jeder Raum vorhanden, Nachbarn auf den richtigen Seiten, jede Verbindung gezeichnet, Türen und Eingänge auf den richtigen Wänden. Wiederholen Sie dies, bis es richtig ist. Fahren Sie nicht mit einem Layout fort, das Sie nicht angesehen haben.
Schritt 3: Texturen
python p2p.py textures PROJEKT
Dies zeichnet die Oberflächentexturen und Dekorationen per Code, in wenigen Sekunden. Mit einem ComfyUI, das doctor --comfy URL bestanden hat, fügen Sie --comfy URL hinzu, um sie stattdessen malen zu lassen (langsamer, reichhaltiger). Führen Sie dies vor dem ersten Bau aus; wenn Sie später Texturen neu erstellen, bauen Sie erneut.
Öffnen Sie zwei oder drei von PROJEKT/textures/_preview/<textur>_tiled.png (concrete_floor, stone_wall, rust_metal, planks, tile, ...) und wählen Sie Boden- und Wandmaterialien, die zum Ort passen; setzen Sie sie als floor und wall in layout.json, für den Ort oder pro Raum. Die Materialtabelle in docs/kit-reference.md listet jedes Material und die verwendete Textur auf.
Schritt 4: props.py, dann bauen
props.py enthält eine Funktion pro Raum, benannt room_<id>, die platziert, was das Briefing für diesen Raum auflistet. docs/props.md erklärt das Kit und zeigt jedes fertige Prop; docs/kit-reference.md listet jeden Aufruf auf; examples/brine-chapel/props.py ist ein vollständiges Modul. Ein minimaler Raum:
def room_3(r, rng, P):
mb = MB("r3_props") # ein Mesh-Builder: Festkörper hinzufügen, dann ein Objekt erstellen
pillar(mb, r.minx + 2, r.cy, h=r.h) # fertige Props nehmen x, y in Metern ...
altar(mb, T(r.cx, r.maxy - 2, 0, rz=0)) # ... oder eine Transform T(x, y, z, rz=Winkel)
box(mb, "wood", (r.cx, r.cy, 0.4), (2.0, 1.0, 0.8)) # alles andere: Boxen, Zylinder, Sweeps
mb.obj(P) # P ist die Sammlung dieses Raums
feat("3.altar", r.cx, r.maxy - 2, 1.1) # ein benannter Punkt, an den ein Poster-Callout angehängt werden kann
Was einen Raum auf dem Poster lesbar macht:
- Modellieren Sie, was der Text zuerst nennt, und geben Sie jedem ein
feat(). Fügen Sie dann 3 bis 10 gewöhnliche Dinge hinzu, die sagen, wofür der Raum ist. Ein leerer Raum sieht nach einem Fehler aus. - Formen lesen sich durch Silhouette und Ton. Helle Materialien (
tile,bone,ice,mushroom,glass) drucken weiß, rote (hazard,liquid_acid,emissive_red) drucken in der Akzentfarbe, dunkle drucken schwarz. Dinge, die kleiner als etwa 0,3 m sind, verschwinden. - Halten Sie 1,5 m vor jeder Türöffnung frei und halten Sie Props innerhalb des Raumrechtecks.
- Verwenden Sie
rngfür jede zufällige Wahl, damit jeder Bau identisch ist. - Gruben und Becken benötigen den vierten Parameter:
def room_4(r, rng, P, cut).
python p2p.py build PROJEKT
python p2p.py render PROJEKT closeup --rooms 3,4
build dauert Sekunden und listet die von Ihnen registrierten Feature-Namen auf. Öffnen Sie PROJEKT/build/iso_preview.png (das gesamte Modell, untexturiert) nach jedem Bau und PROJEKT/renders/closeup_<id>.png für jeden Raum, an dem Sie gearbeitet haben. Überprüfen Sie: nichts schwebt, nichts geht durch eine Wand, Türöffnungen sind frei, der Raum ist aus dem Text erkennbar. Ein Python-Fehler in props.py wird mit seiner Zeilennummer ausgegeben; das vollständige Protokoll ist build/build.log.
Nahaufnahmen verwenden die Ansicht und den Schnitt aus poster.json, genau wie das Poster. Wände werden bei cutaway: {wall: 3.2} Metern aufgeschnitten, und jede der beiden dem Betrachter nächsten Wände verbirgt einen Streifen Boden, etwa so breit wie diese Höhe. Das passt zu Hallen. Wenn die Räume klein sind (unter etwa 8 m), senken Sie ihn jetzt auf 1,5 oder 2, oder alles entlang der nahen Wände verschwindet.
Schritt 5: poster.json, dann das Poster
Bearbeiten Sie die Vorlage: Titel, Untertitel, Fußzeile, ein Callout pro bemerkenswertem Feature und die Textboxen. docs/poster.md hat jeden Schlüssel.
- Ein Callout ist
{"feature": "3.altar", "text": "Salzaltar"}; der Feature-Name ist einer, den Sie mitfeat()registriert haben. Fügen Sie"gm_only": truehinzu, um es von der Spielerversion fernzuhalten. Halten Sie den Text unter etwa acht Wörtern. boxenthält die Notizen des Spielleiters ("gm": eine Begegnungstabelle, Timer, die einzeilige Wahrheit) und was den Spielern gesagt wird ("player"). Jeweils sechs bis acht kurze Zeilen.- Die Spieler-Version entfernt
gm_only-Callouts und als"secret"markierte Verbindungen. Die Kunst ist für beide gleich, daher wird ein geheimer Raum trotzdem gezeichnet; verstecken Sie seinen Namen mit"room_labels": {"5": {"gm": "Ossarium", "player": ""}}und sagen Sie dem Benutzer, dass der Raum selbst sichtbar ist. - Wählen Sie eine Palette, die zum Ort passt (Papier, Tinte, Weiß, Akzent), oder behalten Sie die Standard-Acid-Gelb-Grün-Farbe.
size_inist das Blatt in Zoll,[36, 24]sofern der Benutzer keine andere Größe verlangt hat. Beschriftungen schrumpfen mit dem Blatt; bei einem kleinen, erhöhen Sie"label_scale", bis die Callouts angenehm zu lesen sind.
python p2p.py poster PROJEKT --dpi 100
Öffnen Sie PROJEKT/out/poster_gm.png und poster_player.png. Überprüfen und beheben Sie in poster.json:
| Problem | Behebung |
|---|---|
| Eine Raumbeschriftung überdeckt das Wichtige im Raum | "room_label_offsets": {"3": [dx, dy]}, in Metern Osten und Norden. In der Standardansicht ist Osten rechts-oben auf dem Blatt und Norden links-oben: [d, -d] bewegt eine Beschriftung nach rechts, [d, d] nach oben |
| Ein Callout-Tag sitzt auf etwas | "side": "nw" bei diesem Callout setzt sein Tag auf diese Seite des Punktes (n ist oben auf dem Blatt); oder kürzen, zusammenführen oder Callouts in einem überfüllten Raum entfernen |
| Dinge entlang der nahen Wände sind verborgen | senken Sie "cutaway": {"wall": 1.6}, dann rendern Sie erneut |
| Beschriftungen zu klein oder zu groß für den Ort | "label_scale": 1.3 |
| Titel, Box oder Legende sitzt auf der Kunst | "corners": {"title": "tl", "box": "br", "legend": "bl"}, oder verkleinern Sie die Kunst mit "art_box" |
| Die interessante Seite des Ortes zeigt weg | "view": {"azimuth": 135} (versuchen Sie -45, 45, 135, -135), dann rendern Sie erneut |
| Hohe Props verbergen, was dahinter ist | "cutaway": {"props": {"3": 4.0}} schneidet die Props von Raum 3 bei 4 m ab |
| Gesamtdruck zu dunkel oder zu blass | "exposure": 1.15 (heller) oder 0.9 (dunkler) |
| Ein Callout zeigt ins Nichts | seine feat()-Koordinaten in props.py sind falsch; beheben, bauen, rendern |
Nachdem Sie nur Text oder Beschriftungen geändert haben, fügen Sie --reuse-render hinzu, um das Rendern zu überspringen. Nachdem Sie layout.json, props.py, die Ansicht oder den Schnitt geändert haben, bauen und rendern Sie erneut. Wenn der Entwurf richtig ist:
python p2p.py poster PROJEKT --dpi 200
Dies schreibt out/poster_gm, poster_player und poster_bare als PNG und JPEG in Blattgröße (36 x 24 Zoll sind 7200 x 4800 Pixel). Öffnen Sie das finale GM-Poster noch einmal, bevor Sie Bericht erstatten.
Optionale Extras
- Schlachtkarten.
python p2p.py render PROJEKT planergibt eine Draufsicht des Ortes (renders/plan.png);render PROJEKT rooms --rooms 3ergibt einen Raum bei 70 Pixeln pro Meter (renders/room_3.png). - Raumgemälde (benötigt ComfyUI mit dem Tiefensteuerungs-LoRA; siehe docs/comfyui.md). Schreiben Sie
paint.jsonmit einem Satz pro Raum, dann:python p2p.py render PROJEKT eyeundpython p2p.py paint PROJEKT --comfy URL. Die Gemälde inout/paintings/behalten das Layout jedes Raums bei, weil die Tiefenkarte des Modells sie steuert.--strength(Standard 1,2, nutzbarer Bereich 1,0 bis 1,4) legt fest, wie fest.
Bericht erstatten
Geben Sie dem Benutzer: die Pfade der Poster; was Sie geschätzt oder erfunden haben (Größen, Positionen, alles, was der Text offen ließ); alles in den Richtlinien, was Sie nicht tun konnten; und wie man Dinge ändert (die Dateien bearbeiten, den Befehl erneut ausführen).
Wenn etwas schief geht
| Nachricht oder Symptom | Ursache und Behebung |
|---|---|
Blender: MISSING | Installieren Sie es oder setzen Sie die Umgebungsvariable BLENDER auf die ausführbare Datei: docs/setup.md |
layout.json has errors beim Bau | Führen Sie check aus; jede Zeile sagt, was zu ändern ist |
callout ... names feature ..., which props.py never registered | Schreibweise weicht vom feat()-Namen ab; build gibt die gültigen Namen aus |
| Oberflächen sind flach grau | textures wurde nicht vor build ausgeführt; führen Sie es aus, dann bauen Sie erneut |
Failed to retain CUDA context, oder die GPU hat keinen Speicher mehr | Ein anderes Programm verwendet die GPU: fügen Sie --device cpu hinzu, oder --gpu NAME, um eine Karte auszuwählen |
no GPU device matching ... | Der für --gpu angegebene Name passt zu keiner Karte; doctor listet sie auf |
| Das Rendern ist langsam | Es ist auf der CPU. Entwurf mit --dpi 100; das Finale wird trotzdem fertig, nur später |
| Ein Prop ist oben flach abgeschnitten | Es ist höher als der Schnitt; das ist beabsichtigt. Erhöhen Sie "cutaway": {"wall": ...} für diesen Raum, wenn Sie die Spitze sehen wollen, oder lassen Sie es für einen abgeschnittenen Effekt. |