Page to poster
Vous lisez l'aventure et écrivez cinq petits fichiers qui décrivent le lieu. Le code de ce dossier les vérifie, construit un modèle 3D dans Blender en mode sans tête, le rend et compose l'affiche.
aventure (PDF/texte) + directives
-> brief.md ce que le texte dit du lieu (vous écrivez)
-> layout.json salles, passages, entrées, en mètres (vous écrivez ; `check` valide et le dessine)
-> props.py ce qui se trouve dans chaque salle (vous écrivez ; `build` le modélise)
-> poster.json titre, étiquettes, légendes, boîte de texte (vous écrivez ; `poster` rend et compose)
-> out/poster_gm.png, poster_player.png, poster_bare.png (+ .jpg)
p2p.py se trouve dans ce dossier. Appelez-le par son chemin complet depuis le répertoire de travail de l'utilisateur, afin que les dossiers de projet atterrissent là et pas ici ; les commandes ci-dessous écrivent python p2p.py par souci de brièveté. Utilisez python3 là où python n'est pas Python 3.
Règles qui s'appliquent tout au long du processus
- Regardez chaque image que vous produisez. Chaque étape écrit une image ; ouvrez-la avec votre outil de lecture d'images avant de continuer. Les étapes nomment le fichier. La plupart des erreurs sont évidentes sur l'image et invisibles dans les nombres.
- Mètres, +x est, +y nord, sol à z = 0. Les angles dans
props.pysont en radians. - Dites ce que vous avez estimé. Les aventures donnent rarement des tailles ou des positions exactes. Estimez, écrivez « est. » dans
brief.md, et listez les estimations lorsque vous faites votre rapport. Ne présentez jamais un fait inventé comme provenant du livre. - Blender s'exécute en mode sans tête via
p2p.py. N'ouvrez pas sa fenêtre et n'utilisez pas de serveur MCP Blender. - Les brouillons sont peu coûteux. Affiches en brouillon à
--dpi 100; rendez la version finale à--dpi 200une fois le brouillon correct. - Le dossier du projet contient le texte et les cartes de l'aventure. Gardez-le en dehors des dépôts publics, sauf si l'aventure vous appartient.
Étape 0 : vérifier la machine
python p2p.py doctor
Il doit se terminer par Core pipeline: ready. Si des paquets Python sont manquants : pip install -r requirements.txt. Si Blender est manquant, suivez docs/setup.md. Aucun GPU n'est nécessaire (le rendu se fait sur le CPU), et ComfyUI est optionnel : ne passez --comfy URL que si l'utilisateur vous en a fourni une (docs/comfyui.md).
Étape 1 : démarrer le projet et lire la source
python p2p.py new PROJET --source aventure.pdf --pages 53-56
PROJET est un nouveau dossier pour cette carte, par exemple cartes/le-nom-du-site dans le répertoire de travail de l'utilisateur. --pages sont les numéros de page du PDF (la première page est 1) pour le lieu à cartographier ; omettez-le pour un PDF court. Une source texte ou Markdown est copiée telle quelle. La commande écrit les modèles pour les cinq fichiers et, pour un PDF, source/page_NNN.txt et source/page_NNN.png.
Lisez tout le texte. Ensuite, regardez chaque image de page : les cartes, diagrammes et encadrés ne se trouvent que dans les images. Si le livre a une carte, cette carte détermine où se trouvent les salles ; le texte détermine ce qu'elles contiennent.
Remplissez guidelines.md à partir de ce que l'utilisateur a demandé ; tout ce qu'il n'a pas mentionné conserve sa valeur par défaut. Ne demandez à l'utilisateur que si vous ne pouvez pas déterminer quel lieu cartographier.
Remplissez brief.md : une ligne par salle, une par connexion, une par entrée. Citez les numéros de page. C'est l'étape où vous décidez ce qui est donné et ce qui est estimé.
Tailles lorsque le texte n'en donne aucune : une porte fait 1 m, un couloir 2,5 à 3,5 m, une cellule ou un bureau 4 x 5 m, une salle ordinaire 6 x 8 m, une grande salle 15 x 25 m, une caverne ou un hangar 30 x 50 m. Plafonds : 3 m pour l'ordinaire, 5 à 8 m pour les grandes salles. Un carré de carte mesure généralement 5 pieds (1,5 m) dans les jeux fantastiques ; un « pas » mesure environ un mètre.
Étape 2 : layout.json
Remplacez le modèle par les salles, passages et entrées du site. docs/layout.md contient toutes les clés. Deux projets complets pour apprendre : examples/brine-chapel/ (un donjon de pierre, à partir d'un texte sans carte) et examples/kestrel-9/ (une station préfabriquée, à partir d'un PDF avec une carte schématique). Les essentiels :
- Une salle est un rectangle aligné sur les axes de sol dégagé :
« min »est son coin sud-ouest,« max »son coin nord-est. Laissez au moins 0,6 m (un mur) entre deux salles. - Un lien relie deux salles le long d'un
« path »de points. Le premier point se trouve sur le bord de la sallea, le dernier sur le bord de la salleb; le chemin quitte chaque salle à angle droit par rapport au mur.« kind »estopen,blocked(un effondrement le bouche) ouvent(un conduit ou un passage rampant, de salle à salle ;« z »définit sa hauteur).« doors » : [« a », « b »]place des portes à ces extrémités.« secret » : truemarque un lien que les joueurs ne doivent pas voir : ses portes deviennent des portes secrètes et l'affiche joueur omet son tracé. - Là où trois passages ou plus se rencontrent, nommez l'endroit sous
« junctions »et terminez les chemins là. - Une entrée est un moyen d'entrer depuis l'extérieur de la carte :
stairs,ramp,tunneloudoorsur un mur (« side » : « N|S|E|W »,« at »: position le long de ce mur), ou unshaftà un point à l'intérieur d'une salle. Un passage qui quitte la carte et est effondré est untunnelavec« blocked » : true. - Une salle qui n'est pas un rectangle : donnez-lui son rectangle englobant, puis façonnez-la dans
props.py(cave_fillpour les cavernes et effondrements,partitionpour les murs intérieurs), ou divisez-la en deux salles reliées par un lien court et large. - Une affiche montre un seul niveau. Pour un site à plusieurs niveaux, faites un projet par niveau et reliez-les par des entrées étiquetées « Escaliers vers le niveau 2 ».
Disposez le site de manière à ce qu'il soit compact et à peu près aussi profond que large ; cela remplit le mieux une feuille 3:2 dans la vue isométrique. Placez la première salle près de (0, 0) et travaillez vers l'extérieur sur une grille de 1 m.
python p2p.py check PROJET
Corrigez chaque erreur (chaque message indique quoi modifier). Ouvrez ensuite PROJET/build/layout_check.png et comparez-le avec la carte du livre ou avec votre brief : chaque salle présente, les voisins du bon côté, chaque connexion dessinée, les portes et entrées sur les bons murs. Répétez jusqu'à ce que ce soit correct. Ne continuez pas avec une disposition que vous n'avez pas regardée.
Étape 3 : textures
python p2p.py textures PROJET
Cela dessine les textures de surface et les décalcomanies par code, en quelques secondes. Avec un ComfyUI qui a passé doctor --comfy URL, ajoutez --comfy URL pour les faire peindre à la place (plus lent, plus riche). Exécutez ceci avant la première construction ; si vous refaites les textures plus tard, reconstruisez.
Ouvrez deux ou trois des PROJET/textures/_preview/<texture>_tiled.png (concrete_floor, stone_wall, rust_metal, planks, tile, ...) et choisissez des matériaux de sol et de mur qui conviennent au lieu ; définissez-les comme « floor » et « wall » dans layout.json, pour le site ou par salle. Le tableau des matériaux dans docs/kit-reference.md liste chaque matériau et la texture qu'il utilise.
Étape 4 : props.py, puis build
props.py contient une fonction par salle, nommée room_<id>, qui place ce que le brief liste pour cette salle. docs/props.md explique le kit et montre chaque accessoire prêt à l'emploi ; docs/kit-reference.md liste chaque appel ; examples/brine-chapel/props.py est un module complet. Une salle minimale :
def room_3(r, rng, P):
mb = MB("r3_props") # un constructeur de maillage : ajoutez des solides, puis créez un objet
pillar(mb, r.minx + 2, r.cy, h=r.h) # les accessoires prêts à l'emploi prennent x, y en mètres ...
altar(mb, T(r.cx, r.maxy - 2, 0, rz=0)) # ... ou une transformée T(x, y, z, rz=angle)
box(mb, "wood", (r.cx, r.cy, 0.4), (2.0, 1.0, 0.8)) # tout le reste : boîtes, cylindres, balayages
mb.obj(P) # P est la collection de cette salle
feat("3.altar", r.cx, r.maxy - 2, 1.1) # un point nommé auquel une légende d'affiche peut s'accrocher
Ce qui rend une salle lisible sur l'affiche :
- Modélisez ce que le texte nomme en premier, et donnez à chacun un
feat(). Ajoutez ensuite 3 à 10 choses ordinaires qui disent à quoi sert la salle. Une salle vide ressemble à une erreur. - Les formes se lisent par silhouette et tonalité. Les matériaux brillants (
tile,bone,ice,mushroom,glass) s'impriment en blanc, les rouges (hazard,liquid_acid,emissive_red) s'impriment dans l'encre d'accent, les foncés s'impriment en noir. Les choses plus petites qu'environ 0,3 m disparaissent. - Gardez 1,5 m de dégagement devant chaque porte, et gardez les accessoires à l'intérieur du rectangle de la salle.
- Utilisez
rngpour chaque choix aléatoire afin que chaque construction soit identique. - Les fosses et les bassins ont besoin du quatrième paramètre :
def room_4(r, rng, P, cut).
python p2p.py build PROJET
python p2p.py render PROJET closeup --rooms 3,4
build prend quelques secondes et liste les noms des caractéristiques que vous avez enregistrées. Ouvrez PROJET/build/iso_preview.png (le modèle entier, non texturé) après chaque construction, et PROJET/renders/closeup_<id>.png pour chaque salle sur laquelle vous avez travaillé. Vérifiez : rien ne flotte, rien ne traverse un mur, les portes sont dégagées, la salle est reconnaissable d'après le texte. Une erreur Python dans props.py est imprimée avec son numéro de ligne ; le journal complet est build/build.log.
Les gros plans utilisent la vue et la coupe de poster.json, comme le fera l'affiche. Les murs sont ouverts à « cutaway » : {« wall » : 3.2} mètres, et chacun des deux murs les plus proches du spectateur cache une bande de sol à peu près aussi large que cette hauteur. Cela convient aux grandes salles. Si les salles sont petites (moins d'environ 8 m), abaissez-le maintenant, à 1,5 ou 2, sinon tout ce qui se trouve le long des murs proches disparaît.
Étape 5 : poster.json, puis l'affiche
Modifiez le modèle : titre, sous-titre, pied de page, une légende par caractéristique notable, et les boîtes de texte. docs/poster.md contient toutes les clés.
- Une légende est
{« feature » : « 3.altar », « text » : « Autel de sel »}; le nom de la caractéristique est celui que vous avez enregistré avecfeat(). Ajoutez« gm_only » : truepour le garder hors de la version joueur. Gardez le texte sous environ huit mots. « box »contient les notes du MJ (« gm »: une table de rencontre, des minuteries, la vérité en une ligne) et ce qui est dit aux joueurs (« player »). Six à huit lignes courtes chacun.- La version joueur supprime les légendes
gm_onlyet les liens marqués« secret ». L'illustration est la même pour les deux, donc une salle secrète est toujours dessinée ; cachez son nom avec« room_labels » : {« 5 » : {« gm » : « Ossuaire », « player » : « »}}et dites à l'utilisateur que la salle elle-même apparaît. - Choisissez une palette qui convient au lieu (papier, encre, blanc, accent), ou conservez le défaut jaune-vert acide.
« size_in »est la feuille en pouces,[36, 24]sauf si l'utilisateur a demandé une autre taille. Les étiquettes rétrécissent avec la feuille ; sur une petite, augmentez« label_scale »jusqu'à ce que les légendes soient confortables à lire.
python p2p.py poster PROJET --dpi 100
Ouvrez PROJET/out/poster_gm.png et poster_player.png. Vérifiez et corrigez dans poster.json :
| Problème | Correctif |
|---|---|
| Une étiquette de salle couvre ce qui est important dans la salle | « room_label_offsets » : {« 3 » : [dx, dy]}, en mètres vers l'est et le nord. Dans la vue par défaut, l'est est à droite et en haut sur la feuille, le nord est à gauche et en haut : [d, -d] déplace une étiquette vers la droite, [d, d] vers le haut |
| Une étiquette de légende repose sur quelque chose | « side » : « nw » sur cette légende place son étiquette de ce côté du point (n est le haut de la feuille) ; ou raccourcissez, fusionnez ou supprimez les légendes dans une salle bondée |
| Les éléments le long des murs proches sont cachés | abaissez « cutaway » : {« wall » : 1.6}, puis rendez à nouveau |
| Étiquettes trop petites ou trop grandes pour le site | « label_scale » : 1.3 |
| Le titre, la boîte ou la légende repose sur l'illustration | « corners » : {« title » : « tl », « box » : « br », « legend » : « bl »}, ou réduisez l'illustration avec « art_box » |
| Le côté intéressant du site fait face à l'opposé | « view » : {« azimuth » : 135} (essayez -45, 45, 135, -135), puis rendez à nouveau |
| Les accessoires hauts cachent ce qui est derrière | « cutaway » : {« props » : {« 3 » : 4.0}} coupe les accessoires de la salle 3 à 4 m |
| L'impression entière est trop sombre ou trop pâle | « exposure » : 1.15 (plus clair) ou 0.9 (plus foncé) |
| Une légende ne pointe sur rien | ses coordonnées feat() dans props.py sont erronées ; corrigez, construisez, rendez |
Après avoir modifié uniquement le texte ou les étiquettes, ajoutez --reuse-render pour ignorer le rendu. Après avoir modifié layout.json, props.py, la vue ou la coupe, construisez et rendez à nouveau. Lorsque le brouillon est correct :
python p2p.py poster PROJET --dpi 200
Cela écrit out/poster_gm, poster_player et poster_bare en PNG et JPEG à la taille de la feuille (36 x 24 pouces correspond à 7200 x 4800 pixels). Ouvrez l'affiche MJ finale une fois de plus avant de faire votre rapport.
Extras optionnels
- Cartes de combat.
python p2p.py render PROJET plandonne un plan vu de dessus du site (renders/plan.png) ;render PROJET rooms --rooms 3donne une salle à 70 pixels par mètre (renders/room_3.png). - Peintures de salle (nécessite ComfyUI avec le LoRA de contrôle de profondeur ; voir docs/comfyui.md). Écrivez
paint.jsonavec une phrase par salle, puis :python p2p.py render PROJET eyeetpython p2p.py paint PROJET --comfy URL. Les peintures dansout/paintings/conservent la disposition de chaque salle car la carte de profondeur du modèle les guide.--strength(par défaut 1,2, plage utile 1,0 à 1,4) définit la fermeté.
Rapport
Donnez à l'utilisateur : les chemins des affiches ; ce que vous avez estimé ou inventé (tailles, positions, tout ce que le texte laissait ouvert) ; tout ce que vous n'avez pas pu faire dans les directives ; et comment modifier les choses (modifiez les fichiers, relancez la commande).
Quand quelque chose tourne mal
| Message ou symptôme | Cause et correctif |
|---|---|
Blender: MISSING | Installez-le ou définissez la variable d'environnement BLENDER vers l'exécutable : docs/setup.md |
layout.json has errors lors de la construction | Exécutez check ; chaque ligne indique quoi modifier |
callout ... names feature ..., which props.py never registered | L'orthographe diffère du nom feat() ; build imprime les noms valides |
| Les surfaces sont gris plat | textures n'a pas été exécuté avant build ; exécutez-le, puis reconstruisez |
Failed to retain CUDA context, ou le GPU manque de mémoire | Un autre programme utilise le GPU : ajoutez --device cpu, ou --gpu NOM pour choisir une carte |
no GPU device matching ... | Le nom donné à --gpu ne correspond à aucune carte ; doctor les liste |
| Le rendu est lent | Il est sur le CPU. Brouillon à --dpi 100 ; la version finale finit quand même, juste plus tard |
| Un accessoire est coupé net en haut | Il est plus haut que la coupe ; c'est intentionnel. Relevez la coupe du mur, ou ajoutez une coupe spécifique pour accessoires |
| Les textures ne collent pas à la géométrie | Reconstruisez après avoir changé la disposition ou les accessoires : le build refait les UV |
| Le script s'arrête sans message | Regardez build/build.log et out/out.log |