ttrpg-tools/docs/csv.md

9.4 KiB
Raw Permalink Blame History

CSV 编写说明

TTRPG Tools 使用带有 YAML Front Matter 的 CSV 格式来定义卡牌/表格数据。这种格式支持在 CSV 文件头部定义元数据、字段配置和共享属性。

文件结构

---
# YAML Front Matter可选
fields:
  - name: 字段名
    description: 字段描述
deck:
  size: 54x86
  grid: 5x8
shared_prop: 共享属性值
---
# CSV 数据
label,body,field1,field2
1内容值 1值 2

YAML Front Matter

Front Matter 是可选的,位于文件开头,使用 --- 包裹的 YAML 格式内容。

基本结构

---
fields:
  - name: name
    description: 卡牌名称
  - name: effect
    description: 效果描述
    examples: ["造成 5d6 伤害", "恢复 2d4 生命值"]
deck:
  size: 63x88
  grid: 5x5
  bleed: 1
  padding: 2
custom_prop: 自定义属性
---

Front Matter 属性

fields - 字段定义

定义 CSV 中各列的含义和配置。

fields:
  - name: name          # 字段名称(英文,用于 CSV 列名)
    description: 卡牌名称  # 字段描述
    examples:           # 示例值列表(可选)
      - 火球术卷轴
      - 治疗药水
    dataType: word      # 数据类型可选word/paragraph/number/symbol/symbol_list
    function: identify  # 字段功能可选identify/compare/flavor/rule

数据类型说明:

类型 说明 示例
word 词语 - 短文本 "火球术"、"战士"、"传说"
paragraph 文本段落 - 长描述 "造成 5d6 点火焰伤害,范围内的所有生物进行敏捷豁免"
number 数字 - 可比较的数值 3、5、10
symbol 单一符号 - 图标/标记 🔥⚔️🛡️
symbol_list 符号列表 - 多个图标/标记 🔥🔥🔥⚔️🛡️💫

字段功能说明:

功能 说明 示例
identify 辨识 - 用于识别卡牌身份 名称、编号、唯一标识
compare 比较 - 用于游戏机制中的数值比较 费用、攻击力、防御力
flavor 游戏风味描述 - 提供背景故事/氛围 背景故事、引言、lore
rule 规则确认 - 明确游戏规则相关的信息 效果文本、触发条件、限制

deck - 卡牌显示配置

用于 :md-deck 组件的默认配置。

deck:
  size: 63x88           # 卡牌尺寸mm格式 "宽 x 高"
  grid: 5x5             # 网格布局,格式 "列 x 行"
  bleed: 1              # 出血边距mm
  padding: 2            # 内边距mm
  shape: rectangle      # 卡牌形状rectangle/circle/hex/diamond
  layers: "name:1-2,14" # 图层配置(可选)
  back_layers: ""       # 背面图层配置(可选)

图层配置语法遵循layer:1,1-5,8f8s格式:

  • layer:图层名称,多个图层用空格分隔
  • 1,1-5,8:网格范围,覆盖卡牌排版网格中的指定区域。
  • f8字体大小使用8mm字体。可选。
  • s图层朝向有nwse东西南北四种方向描述文字上侧的朝向默认为n北方。

自定义属性

可以在 Front Matter 中定义任意自定义属性,这些属性会被自动应用到所有卡牌行。

---
game_system: 龙与地下城 5e
author: DM_Name
version: 1.0
---

CSV 数据部分

基本格式

label,body,field1,field2
1内容值 1值 2

必需列

label

每行的唯一标识,用于查找和修改卡牌。

  • 可以是数字:1, 2, 3
  • 可以是文本:card_001, npc_villager
  • 支持分组前缀:forest_1, dungeon_1

body

卡牌的主要内容,支持 Markdown 格式。

label,body
1,"### 标题

**加粗文本**

- 列表项 1
- 列表项 2"

可选列

labelbody 外,可以定义任意自定义列,列名在 Front Matter 的 fields 中定义。

label,body,name,type,cost,effect
1完整内容火球术法术3造成 5d6 火焰伤害

变量语法

body 列或 Front Matter 中,可以使用 {{prop}} 语法引用其他列的值或 Front Matter 中的属性。

引用同行其他列

label,body,adj,noun
1,"**{{adj}}** 的{{noun}}",高大,战士
2,"{{adj}}的{{noun}}",矮小,法师

渲染后:

  • 第 1 行:高大 的战士
  • 第 2 行:矮小的法师

引用 Front Matter 属性

---
game_system: D&D 5e
author: DM_Name
---
label,body
1,"这是一个{{game_system}}冒险,由{{author}}创建"

渲染后:这是一个 D&D 5e 冒险,由 DM_Name 创建

随机引用remix 模式)

:md-table 组件中,可以使用 remix 属性启用随机引用:

:md-table[./data.csv]{remix=true}

此时 {{prop}} 会从所有行中随机选择一行的值,而不是使用当前行的值。


分组支持

可以使用额外的列来对数据进行分组。

group,label,body
森林小径1狼群袭击
森林小径2荆棘陷阱
森林小径3迷路
塔楼楼梯1台阶坍塌
塔楼楼梯2落石

:md-table 组件中,可以使用 group 属性来筛选显示特定组的数据:

:md-table[./encounters.csv]{group="森林小径"}

特殊字符处理

包含逗号的值

使用双引号包裹:

label,body
1,"Hello, world"

包含双引号的值

使用两个双引号转义:

label,body
1,"他说:""你好"""

包含换行的值

使用双引号包裹,直接写入换行:

label,body
1,"### 标题

这是第一段

这是第二段"

包含 # 注释

CSV 解析器会将 # 开头的行视为注释,但如果 # 在双引号内则正常处理:

label,body
1,"# 这不是注释"
# 这是真正的注释

完整示例

示例 1魔法物品卡牌组

---
fields:
  - name: name
    description: 物品名称
    dataType: word
    function: identify
  - name: type
    description: 物品类型
    dataType: word
    function: identify
    examples: [武器,防具,饰品,消耗品]
  - name: rarity
    description: 稀有度
    dataType: word
    function: compare
    examples: [普通,稀有,史诗,传说]
  - name: cost
    description: 价格
    dataType: number
    function: compare
  - name: effect
    description: 效果描述
    dataType: paragraph
    function: rule
deck:
  size: 63x88
  grid: 5x5
  shape: rectangle
game_system: D&D 5e
---
label,body,name,type,rarity,cost,effect
1,"### 火球术卷轴

一张泛黄的羊皮纸,上面绘有火焰符文。",火球术卷轴消耗品稀有150,"投掷后对 20 尺内所有生物造成 8d6 火焰伤害(敏捷豁免减半)"
2,"### 治疗药水

红色液体在玻璃瓶中翻滚,散发着温暖的光芒。",治疗药水消耗品普通50,"饮用后恢复 2d4+2 点生命值"
3,"### +1 长剑

剑刃闪烁着微光,握柄包裹着精致的皮革。",+1 长剑武器稀有300,"攻击和伤害检定 +1"

示例 2随机遭遇表

---
fields:
  - name: group
    description: 遭遇地点分组
  - name: title
    description: 遭遇标题
  - name: type
    description: 遭遇类型
deck:
  size: 54x86
  grid: 4x6
---
group,label,body,title,type
森林小径1,"### 狼群袭击

三只灰狼从灌木丛中扑出。

**交互**战斗3 只巨狼)或逃脱(敏捷检定 3/2

**风险**:失败受到 d8 撕咬伤害",狼群袭击,战斗
森林小径2,"### 荆棘陷阱

带刺藤蔓缠住你的双腿。

**交互**:挣脱(力量检定 3/2

**风险**:失败受到 1 点体质损伤",荆棘陷阱,陷阱
森林小径3,"### 迷路

浓雾弥漫,你失去了方向。

**交互**:寻找路径(感知检定 3/2

**风险**:失败受到 1 点感知损伤",迷路,事件
塔楼楼梯1,"### 台阶坍塌

脚下的石阶突然碎裂。

**交互**:保持平衡(敏捷检定 3/1

**风险**:失败受到 1 点敏捷损伤",台阶坍塌,陷阱

示例 3NPC 名录

---
fields:
  - name: name
    description: NPC 名称
  - name: role
    description: 角色定位
  - name: location
    description: 出现地点
deck:
  size: 54x86
  grid: 4x6
---
label,body,name,role,location
1,"### 老妇人玛拉

**类型**:信息提供者/商人

**位置**:村庄入口

**出售**:草药、治疗药水

**情报**:知道关于森林的警告",老妇人玛拉,商人,村庄入口
2,"### 护卫队长塞里克

**类型**:任务发布者

**位置**:酒馆二楼

**任务**:调查废弃庄园

**秘密**:知道血契的真相",塞里克,任务发布者,酒馆

与组件集成

:md-deck 组件

:md-deck[./magic-items.csv]{size="63x88" grid="5x5" roll=true}
  • roll=true:添加随机抽卡按钮

:md-table 组件

:md-table[./encounters.csv]{group="森林小径" remix=true}
  • group:筛选特定组的数据
  • remix=true:启用随机引用模式

最佳实践

  1. 使用有意义的 label:便于后续查找和修改
  2. 在 Front Matter 中定义所有字段:便于工具理解和处理
  3. 使用 {{prop}} 变量:减少重复内容,支持动态组合
  4. 合理使用分组:便于筛选和管理大量数据
  5. 保持 body 的 Markdown 格式一致:确保渲染效果统一
  6. 为字段添加 examples:帮助 AI 工具生成内容时参考