Community图像github.com

michaelweber/page-to-poster

将书面冒险场景(PDF页面或文本)与粗略制图指南转换为3D Blender模型和印刷就绪的等轴测剖视图海报,采用丝网印刷风格,包含GM和玩家版本。

page-to-poster 是什么?

该AI代理技能(Page to Poster)旨在将RPG冒险中的文字描述或PDF页面转化为专业的3D模型和印刷级海报。它通过一个完整的工作流程实现:AI首先读取冒险资料并编写五个描述文件(节点布局、房间道具、海报排版等),然后利用无头Blender自动构建3D模型、渲染并合成海报。该技能支持多种平台,包括Claude Code、Cursor和Codex等AI代理工具,通过命令行接口与用户协作。其核心优势在于将繁琐的地图制作过程自动化,同时保留创意控制——AI估算尺寸并标注,用户可调整布局、道具和海报样式。最终输出包括GM版(含秘密信息)和玩家版(隐藏秘密)的PNG/JPEG海报,以及可选的俯视战斗地图和房间彩绘(需ComfyUI支持)。整个流程强调可视化检查,每一步生成图像供AI验证,确保准确性。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/michaelweber/page-to-poster/tree/HEAD

Installed? Explore more 图像 skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

页面到海报

你阅读冒险资料,编写五个描述地点的小文件。此文件夹中的代码会检查它们,在无头Blender中构建3D模型,渲染并合成海报。

adventure (PDF/text) + guidelines
   -> brief.md        文本对该地点的描述          (你编写)
   -> layout.json    房间、通道、入口,以米为单位 (你编写;`check` 验证并绘制)
   -> props.py       每个房间中摆放的物品       (你编写;`build` 建模)
   -> poster.json    标题、标签、标注、文本框    (你编写;`poster` 渲染并合成)
   -> out/poster_gm.png, poster_player.png, poster_bare.png  (+ .jpg)

p2p.py 位于此文件夹中。请从用户的工作目录通过其完整路径调用它,以便项目文件夹存放在该目录下而非此处;下面的命令简写为 python p2p.py。如果 python 不是 Python 3,请使用 python3。

全程遵守的规则

  1. 检查你生成的每张图片。 每一步都会写入一张图像;在继续之前用你的图像阅读工具打开它。各步骤会命名文件。大多数错误在图片中显而易见,而在数字中却不可见。
  2. 米制,+x 向东,+y 向北,地面 z = 0。 props.py 中的角度为弧度。
  3. 说明你估算的内容。 冒险资料很少给出尺寸或精确位置。进行估算,在 brief.md 中写“est.”,并在汇报时列出估算值。切勿将虚构的事实当作书中的内容。
  4. Blender 以无头模式 通过 p2p.py 运行。不要打开其窗口,也不要使用 Blender MCP 服务器。
  5. 草稿成本低。 以 --dpi 100 制作草稿海报;草稿正确后,以 --dpi 200 渲染最终版。
  6. 项目文件夹存放冒险的文本和地图。除非冒险内容归你所有,否则不要将其放入公共仓库。

步骤 0:检查机器

python p2p.py doctor

它必须以 Core pipeline: ready 结束。如果缺少 Python 包:pip install -r requirements.txt。如果缺少 Blender,请遵循 docs/setup.md。不需要 GPU(渲染会回退到 CPU),ComfyUI 是可选的:仅当用户提供了 URL 时才传递 --comfy URL(docs/comfyui.md)。

步骤 1:启动项目并阅读源资料

python p2p.py new PROJECT --source adventure.pdf --pages 53-56

PROJECT 是为此地图创建的新文件夹,例如用户工作目录中的 maps/the-site-name。--pages 是 PDF 本身的页码(第一页为 1),用于指定要绘制地图的位置;对于短 PDF 可以省略。文本或 Markdown 源文件会被原样复制。该命令会为五个文件写入模板,对于 PDF,还会生成 source/page_NNN.txt 和 source/page_NNN.png。

阅读所有文本。然后查看每页图片:地图、图表和侧边栏仅存在于图片中。如果书中有地图,则地图决定房间的位置;文本决定房间内的内容。

根据用户的请求填写 guidelines.md;用户未提及的内容保留默认值。仅当你不确定要绘制哪个地点时才询问用户。

填写 brief.md:每个房间一行,每个连接一行,每个入口一行。引用页码。在此步骤中,你需要决定哪些是给定的,哪些是估算的。

当文本未给出尺寸时:门宽 1 米,走廊宽 2.5 到 3.5 米,牢房或办公室 4 x 5 米,普通房间 6 x 8 米,大厅 15 x 25 米,洞穴或机库 30 x 50 米。天花板高度:普通房间 3 米,大厅 5 到 8 米。在奇幻游戏中,一个地图方格通常为 5 英尺(1.5 米);一“步”大约为 1 米。

步骤 2:layout.json

将模板替换为地点的房间、通道和入口。docs/layout.md 包含所有键。两个完整的项目可供学习:examples/brine-chapel/(一个石制地牢,来自没有地图的文本)和 examples/kestrel-9/(一个预制站,来自带有草图地图的 PDF)。要点如下:

  • 房间是一个轴对齐的矩形净空区域:"min" 是其西南角,"max" 是其东北角。任意两个房间之间至少留出 0.6 米(一堵墙)。
  • 链接沿着由点组成的 "path" 连接两个房间。第一个点位于房间 a 的边缘,最后一个点位于房间 b 的边缘;路径以与墙壁成直角的方式离开每个房间。"kind" 可以是 open、blocked(坍塌堵塞)或 vent(风道或爬行通道,房间到房间;"z" 设置其高度)。"doors": ["a", "b"] 在两端放置门。"secret": true 标记玩家不可见的链接:其门变为暗门,玩家版海报会省略其路径标记。
  • 在三条或更多通道交汇处,在 "junctions" 下命名该点,并在该点结束路径。
  • 入口是从地图外部进入的方式:可以是墙上的 stairs、ramp、tunnel 或 door("side": "N|S|E|W","at":沿墙的位置),也可以是房间内的 shaft(位于一个点)。离开地图并坍塌的通道是带有 "blocked": true 的 tunnel。
  • 非矩形房间:指定其边界矩形,然后在 props.py 中塑造其形状(洞穴和坍塌使用 cave_fill,内墙使用 partition),或者将其拆分为两个由短而宽的链接连接的房间。
  • 一张海报显示一个层级。对于多层地点,为每个层级创建一个项目,并用标记为“Stairs to level 2”的入口连接它们。

布置地点,使其紧凑且大致深宽相当;这在等轴测视图中最适配 3:2 的纸张。将第一个房间放在 (0, 0) 附近,然后在 1 米的网格上向外扩展。

python p2p.py check PROJECT

修复每个错误(每条消息都会说明要更改的内容)。然后打开 PROJECT/build/layout_check.png 并与书中的地图或你的 brief 进行比较:每个房间都存在,邻居在正确的边上,每个连接都已绘制,门和入口在正确的墙壁上。重复直到正确。不要在没有查看布局的情况下继续。

步骤 3:纹理

python p2p.py textures PROJECT

这会通过代码在几秒钟内绘制表面纹理和贴花。如果 ComfyUI 通过了 doctor --comfy URL,则添加 --comfy URL 使其改为通过绘画生成(较慢,但更丰富)。在首次构建之前运行此命令;如果之后重新生成纹理,需要再次构建。

打开两三个 PROJECT/textures/_preview/<texture>_tiled.png(concrete_floor、stone_wall、rust_metal、planks、tile 等),选择适合该地点的地板和墙壁材料;在 layout.json 中将其设置为整体或每个房间的 "floor" 和 "wall"。docs/kit-reference.md 中的材料表列出了每种材料及其使用的纹理。

步骤 4:props.py,然后构建

props.py 为每个房间包含一个函数,命名为 room_<id>,用于放置 brief 中为该房间列出的物品。docs/props.md 解释了工具包并展示了每个现成的道具;docs/kit-reference.md 列出了每个调用;examples/brine-chapel/props.py 是一个完整的模块。一个最小的房间示例:

def room_3(r, rng, P):
    mb = MB("r3_props")                                  # 一个网格构建器:添加实体,然后创建一个对象
    pillar(mb, r.minx + 2, r.cy, h=r.h)                  # 现成道具以米为单位取 x, y ...
    altar(mb, T(r.cx, r.maxy - 2, 0, rz=0))              # ... 或一个变换 T(x, y, z, rz=angle)
    box(mb, "wood", (r.cx, r.cy, 0.4), (2.0, 1.0, 0.8))  # 其他任何东西:盒子、圆柱体、扫掠体
    mb.obj(P)                                            # P 是这个房间的集合
    feat("3.altar", r.cx, r.maxy - 2, 1.1)               # 一个命名点,海报标注可以固定在上面

使房间在海报上清晰可辨的因素:

  • 首先对文本中命名的物品进行建模,并为每个物品添加一个 feat()。然后添加 3 到 10 个普通物品来说明房间的用途。空的房间看起来像错误。
  • 形状通过轮廓和色调来识别。明亮的材料(tile、bone、ice、mushroom、glass)打印为白色,红色的材料(hazard、liquid_acid、emissive_red)打印为强调色,深色的材料打印为黑色。小于约 0.3 米的物体会消失。
  • 在每个门口前保持 1.5 米的净空,并将道具保持在房间矩形内。
  • 每次随机选择都使用 rng,以确保每次构建都相同。
  • 坑洞和水池需要第四个参数:def room_4(r, rng, P, cut)。
python p2p.py build PROJECT
python p2p.py render PROJECT closeup --rooms 3,4

build 需要几秒钟并列出你注册的特征名称。每次构建后打开 PROJECT/build/iso_preview.png(整个模型,未纹理化),以及为你处理过的每个房间打开 PROJECT/renders/closeup_<id>.png。检查:没有浮空物品,没有物品穿透墙壁,门口畅通,房间可从文本中识别。props.py 中的 Python 错误会连同行号一起打印;完整日志在 build/build.log 中。

特写使用 poster.json 中的视图和剖视图,与海报将使用的相同。墙壁在 "cutaway": {"wall": 3.2} 米处被切开,并且靠近观看者的两面墙各隐藏一个与该高度大致相同宽度的地板条。这适合大厅。如果房间很小(约 8 米以下),请立即降低此值,降至 1.5 或 2,否则靠近墙边的所有物品都会消失。

步骤 5:poster.json,然后制作海报

编辑模板:标题、副标题、页脚、每个显著特征一个标注以及文本框。docs/poster.md 包含所有键。

  • 标注是 {"feature": "3.altar", "text": "Salt altar"};特征名称是你通过 feat() 注册的。添加 "gm_only": true 以将其从玩家版本中移除。文本保持在约八个单词以内。
  • box 包含 GM 的笔记("gm":遭遇表、计时器、一行真相)以及玩家被告知的内容("player")。每个框六到八行简短内容。
  • 玩家版本会删除 gm_only 标注和标记为 "secret" 的链接。两者的艺术作品相同,因此秘密房间仍然会被绘制;使用 "room_labels": {"5": {"gm": "Ossuary", "player": ""}} 隐藏其名称,并告知用户房间本身会显示。
  • 选择适合地点的调色板(纸张、墨水、白色、强调色),或保留默认的酸黄色/绿色。
  • size_in 是纸张的英寸尺寸,[36, 24],除非用户要求其他尺寸。标签会随纸张一起缩小;在小纸张上提高 "label_scale",直到标注易于阅读。
python p2p.py poster PROJECT --dpi 100

打开 PROJECT/out/poster_gm.png 和 poster_player.png。检查并在 poster.json 中修复:

问题修复
房间标签遮盖了房间内的重要物品"room_label_offsets": {"3": [dx, dy]},单位为米,向东和向北。在默认视图中,东方向为纸张的右上方向,北方向为左上方向:[d, -d] 将标签向右移动,[d, d] 向上移动
标注标签位于某个物品上在该标注上设置 "side": "nw",使其标签位于圆点的该侧(n 为纸张的向上方向);或者在拥挤的房间中缩短、合并或删除标注
靠近墙边的物品被隐藏降低 "cutaway": {"wall": 1.6},然后重新渲染
标签对于地点来说太小或太大"label_scale": 1.3
标题、框或图例位于艺术作品上"corners": {"title": "tl", "box": "br", "legend": "bl"},或使用 "art_box" 缩小艺术作品
地点有趣的一面背对观看者"view": {"azimuth": 135}(尝试 -45、45、135、-135),然后重新渲染
高大的道具遮挡了其后的物品"cutaway": {"props": {"3": 4.0}} 将房间 3 的道具在 4 米处切开
整张打印太暗或太浅"exposure": 1.15(更亮)或 0.9(更暗)
标注指向了空处其在 props.py 中的 feat() 坐标有误;修复、构建、重新渲染

仅在更改文本或标签后,添加 --reuse-render 以跳过渲染。更改 layout.json、props.py、视图或剖视图后,需要再次构建和渲染。当草稿正确时:

python p2p.py poster PROJECT --dpi 200

这将以纸张尺寸(36 x 24 英寸为 7200 x 4800 像素)写入 out/poster_gm、poster_player 和 poster_bare 的 PNG 和 JPEG 格式。在汇报前,再次打开最终的 GM 海报。

可选额外功能

  • 战斗地图。 python p2p.py render PROJECT plan 生成地点的俯视平面图 (renders/plan.png);render PROJECT rooms --rooms 3 以每米 70 像素生成单个房间的视图 (renders/room_3.png)。
  • 房间绘画(需要带有深度控制 LoRA 的 ComfyUI;参见 docs/comfyui.md)。为每个房间编写一句描述,写入 paint.json,然后: python p2p.py render PROJECT eye 和 python p2p.py paint PROJECT --comfy URL。 out/paintings/ 中的绘画会保持每个房间的布局,因为模型的深度图会引导它们。--strength(默认 1.2,有效范围 1.0 到 1.4)设置引导强度。

汇报

向用户提供:海报的路径;你估算或虚构的内容(尺寸、位置、文本中未提及的任何内容);guidelines 中你无法做到的事情;以及如何更改内容(编辑文件,重新运行命令)。

当出现问题时

消息或症状原因和修复
Blender: MISSING安装它或将 BLENDER 环境变量设置为可执行文件:docs/setup.md
layout.json has errors on build运行 check;每一行都会说明要更改的内容
callout ... names feature ..., which props.py never registered拼写与 feat() 名称不同;build 会打印有效的名称
表面为平灰色在 build 之前未运行 textures;运行它,然后再次构建
Failed to retain CUDA context,或 GPU 内存不足其他程序正在使用 GPU:添加 --device cpu,或使用 --gpu NAME 选择一张显卡
no GPU device matching ...提供给 --gpu 的名称与任何显卡不符;doctor 会列出它们
渲染速度慢它在 CPU 上运行。以 --dpi 100 制作草稿;最终版仍然会完成,只是较晚
一个道具在顶部被平切它比剖视图高;这是有意为之。提高剖视图墙壁高度或道具切割高度

文档 中的每个页面都有完整的参考。

相关技能