PI

pipeline-generate

Automatically create recognition and action nodes for MaaFramework pipelines.

Install

mkdir -p .claude/skills/pipeline-generate && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/18983" && unzip -o skill.zip -d .claude/skills/pipeline-generate && rm skill.zip

Installs to .claude/skills/pipeline-generate

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Generate MaaFramework Pipeline nodes and recognition snippets from screenshots or observed UI state. Use for OCR node generation, ROI sweep, choosing TemplateMatch/OCR/ColorMatch/CustomRecognition, preserving target-file schema style, and designing `next`/`[JumpBack]` links before merging generated nodes into pipeline JSON.
325 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Advanced

Key capabilities

  • Generate MaaFramework Pipeline nodes from UI state
  • Perform OCR text recognition for node generation
  • Calculate Region of Interest (ROI) for actions
  • Merge generated nodes into pipeline JSON files
  • Sweep for optimal ROI expansion values
  • Choose between TemplateMatch, OCR, ColorMatch, or CustomRecognition

How it works

The skill connects to a device, uses OCR to identify text and calculate ROI, then generates pipeline node JSON based on the target text and action type. It merges these nodes into a specified pipeline file.

Inputs & outputs

You give it
Screenshots or observed UI state, target text, node name, and pipeline file path
You get back
Generated MaaFramework Pipeline nodes in JSON format, merged into the target pipeline file

When to use pipeline-generate

  • Creating OCR nodes
  • Calculating ROI for actions
  • Updating pipeline logic
  • Sweep for best recognition parameters

About this skill

pipeline-generate

概念

Pipeline 由 Node 组成。本 skill 针对OCR 文本识别节点,按 Pipeline 协议生成节点 JSON 并合并到目标 pipeline 文件。

核心流程:连接设备 → ocr() 拿 box → 扩大 ROI → 合并节点

自带脚本(与本 SKILL.md 同目录):

脚本用途
generate_node.py单节点生成(默认 expand=20
generate_sweep.py多 expand 变体扫描,找最佳 ROI

MCP 工具绑定

依赖 maa-mcp MCP 服务。

工具说明
find_adb_device_list / connect_adb_device连接设备
ocr截图 + OCR 一步完成(内部已调 screencap,外部不要再调)
load_pipeline / save_pipeline读/写 pipeline JSON
check_and_download_ocr首次需下载 OCR 模型
run_pipeline测试 pipeline 节点

输入参数

参数必填默认说明
target_text要识别的目标中文文字
node_name节点名(PascalCase)
pipeline_file目标 pipeline 路径(相对 assets/resource/base/pipeline/xxx.json 或绝对路径)
action_typeClickClick / DoNothing / LongPress / Swipe / ClickKey / InputText
expand_offset20ROI 扩边像素(推荐先用 sweep 找最佳
post_delay500
timeout2000
overwriteFalse节点名冲突时是否覆盖

3 步工作流(伪代码)

# === Step 1: 连接设备 ===
from maa_mcp.adb import find_adb_device_list, connect_adb_device
controller_id = connect_adb_device(find_adb_device_list()[0])

# === Step 2: OCR 拿 box + 算 ROI ===
from maa_mcp.vision import ocr
from maa_mcp.download import check_and_download_ocr

ocr_results = ocr(controller_id)
if isinstance(ocr_results, str) and "OCR 模型文件不存在" in ocr_results:
    check_and_download_ocr()
    ocr_results = ocr(controller_id)

matched = [r for r in ocr_results if target_text in (r.text if hasattr(r, "text") else r["text"])]
best = max(matched, key=lambda r: r.score if hasattr(r, "score") else r["score"])
box = best.box if hasattr(best, "box") else best["box"]

# 扩大 ROI(720p 硬编码 + 4 边裁剪)
SCREEN_W, SCREEN_H = 720, 1280
x, y, w, h = box
E = expand_offset
roi = [
    max(0, x - E),
    max(0, y - E),
    min(SCREEN_W - max(0, x - E), w + 2 * E),
    min(SCREEN_H - max(0, y - E), h + 2 * E),
]

# === Step 3: 合并到目标 pipeline ===
from maa_mcp.pipeline_tools import load_pipeline, save_pipeline
from pathlib import Path

PROJECT_ROOT = Path(__file__).resolve().parents[3]
pipeline_path = Path(pipeline_file)
if not pipeline_path.is_absolute():
    pipeline_path = PROJECT_ROOT / "assets" / "resource" / "base" / "pipeline" / pipeline_file

existing = load_pipeline(str(pipeline_path)) or {}
if node_name in existing and not overwrite:
    raise RuntimeError(f"节点 '{node_name}' 已存在")
existing[node_name] = {
    "recognition": "OCR",
    "expected": [target_text],
    "roi": roi,
    "action": action_type,
    "post_delay": post_delay,
    "timeout": timeout,
}
save_pipeline(
    pipeline_json=json.dumps(existing, ensure_ascii=False, indent=4),
    output_path=str(pipeline_path),
    overwrite=True,
)

ROI 扩大示意

原始 box:     ┌────┐
              │ 文字│
              └────┘
扩大后 roi:   ┌──────────┐
              │  ┌────┐  │
              │  │文字│  │
              │  └────┘  │
              └──────────┘

使用流程

脚本位于 .claude/skills/pipeline-generate/,所有命令从项目根目录 f:\workspace\MAAGC 运行。

步骤 1: Sweep 找最佳 expand

# 生成多个 expand 变体的测试 pipeline
python .claude/skills/pipeline-generate/generate_sweep.py "角色" "46,1248,50,30" 0,5,10,15,20,25,30

然后用 run_pipeline 逐个测试每个 Sweep_<text>_eN 节点,BackButton_500ms 返回大地图(详见 pipeline-testing)。记录成功的 expand 值(score ≥ 0.99 为佳)。

步骤 2: 正式生成节点

python .claude/skills/pipeline-generate/generate_node.py "角色" UI_RoleListPage main_ui.json --expand 20 --overwrite

关键经验

历史审查后的生成策略

  • 先判断节点类型,不要默认所有问题都是 OCR:稳定图标/按钮优先 TemplateMatch,颜色状态可用 ColorMatch,动态文本用 OCR,列表/复杂图像后处理用 CustomRecognition。
  • MaaGumballs 的历史文件多为平铺字段风格;M9A HEAD 多为 v5 object-form:action: { type, param }recognition: { type, param }。生成时沿用目标文件的既有风格,不要在同一局部混用两套格式。
  • 生成链路时先画父级 next 状态机:稳定页面、成功态、弹窗 [JumpBack]、加载 [JumpBack]、危险确认分支分开建节点。
  • 对会消耗资源或改变账号状态的节点,默认生成 DoNothing 或单独验证节点;只有用户明确要执行时才生成直接点击确认。
  • 如果需要 Python,先决定是 CustomAction 还是 CustomRecognition:动作/控制流用 CustomAction;识别后处理和动态 box 返回用 CustomRecognition。
  1. ocr() 自动截图:MaaMCP 的 ocr() 工具会自行获取当前画面,调用前不要重复 screencap();如果换了 MCP provider,先读该工具的参数说明确认截图语义。

  2. ROI 不是越大越好:默认 expand=75 会失败(OCR 把"角色"拆成"电"+"色")。多数节点 sweet spot 是 expand=20-30

  3. 特殊节点需要小 ROI:"城堡" expand≥20 全失败,只接受 0-15(上方有图标 M/3.9m/1077/👍 干扰)。

  4. expected 必须匹配当前资源实际显示文本:在 MaaGumballs 中文资源里 ["角色"] 正确、["Role"] 找不到;跨语言项目要按目标资源/locale 写实际 OCR 文本或项目约定的 i18n 形式。

  5. OCR 非确定性:同一 ROI 不同次结果可能不同,timeout: 2000 期间会重试。

  6. OCR 失败不要立刻换 TemplateMatch:先看截图、扫 ROI、检查 expected 与颜色干扰;如果目标本质是稳定图标/按钮,TemplateMatch 本来就是正确选择,不必死守 OCR。

  7. 可滚动 UI 用大 ROI + 父级 orchestrator重要):

    • 不要在 Click 节点的 next 里放 [JumpBack]CastleSwipeDown/Up —— 找不到文字时会死循环滑动
    • 正确模式参考 marry.json 里的 CastleHall 节点:父级 orchestrator 节点的 next 列表里放 [JumpBack]XXXEntry + [JumpBack]XXXSwipeDown + [JumpBack]XXXSwipeUp
    • 滚动容错 ROI 范围参考 CastleHallEntry: [60, 391, 609, 795]
  8. run_pipeline 必须有手动超时意识:超过 ~10 秒不返回要主动停止,可能 ROI/expected 配错或 OCR 引擎卡住。

  9. 改完 pipeline 文件后调 load_pipeline(path) 即可不需要重启 serverrun_pipeline 每次都按 pipeline_path 从磁盘读最新内容,reload 后立即生效。

  10. 可滚动 UI 用统一大 ROI:当多个目标在同一个可滚动列表(如城堡建筑列表)时,所有节点共用同一 ROI [x, top_y, w, full_h],覆盖整个滚动区域。避免每个节点各自 ROI 滚动后失效。前提:每个节点的 expected 文字是唯一的(OCR 按 expected 匹配不会冲突)。

  11. ROI 上边界 ≤ 元素最小 y:目标元素在 y=424 时,ROI y 起点必须 ≤ 424,否则切掉顶部导致 OCR 失败。例:原 ROI [100, 450, ...] 把"城堡管理"切掉 26px → 改为 [100, 400, ...] 通过。

  12. 卡住时截图查看:节点超时、OCR 找不到、行为异常时,调 screencap 看当前屏幕实际状态。可能界面已不在预期页、可能位置已被遮挡。

  13. 跨页面流程用 next 状态机而非 Python orchestration:当一个流程涉及多个页面跳转(如:大地图 → 活动入口 → 难度选择 → 队伍 → 战斗),用 MaaFramework 的 next + [JumpBack] 串节点。不要写 Python for/whilecontext.run_task() 模拟状态机。详见 .claude/skills/pipeline-option/SKILL.md 的「不要做 #10」和 .claude/skills/pipeline-guide/SKILL.md 的「跨页面状态机」。

  14. 跨文件节点引用在 run_pipeline 测试中会失败:MaaFramework 全局加载时所有 assets/resource/base/pipeline/*.json 合并到同一命名空间,[JumpBack]OtherFileNode 能解析。但 run_pipeline 只加载单文件,跨文件引用会报"加载 Pipeline 失败"。应对

    • 单元测试每个节点用 run_pipeline(无跨文件依赖的子流程)是 OK 的
    • 含跨文件引用的状态机流程,集成测试必须用 MaaFramework GUI/CLI 触发
    • 调试时可考虑 MaaCli 命令行运行全 bundle

已验证最优 expand(5 节点实测)

节点expandscore备注
UI_RoleListPage200.9997中部偏左
UI_RoleFormationPage200.998角色右边
UI_CastlePage30.997⚠️ 仅 0-15
UI_TeamPage200.997城堡右边
ClickGoToArchipelago200.991中间大地图按钮

color_filter 减少 OCR 干扰(实战技巧)

场景:ROI 里同时有目标文字 + 周边装饰(如"0/31"绿色能量条 vs "0/23"绿色节点数),OCR 可能误识别装饰色块。

方案:先建一个 ColorMatch 节点(限定像素颜色范围),然后在其他 OCR 节点上加 color_filter 字段引用它。

"AutoSky_GreenCheck": {
    "recognition": "ColorMatch",
    "roi": [558, 802, 157, 45],
    "method": 4,
    "lower": [22, 123, 57],      // RGB 下界(暗绿)
    "upper": [55, 215, 102],     // RGB 上界(亮绿)
    "action": "DoNothing",
    "post_delay": 200,
    "timeout": 2000
},

"AutoSky_CheckEnergyZero": {
    "recognition": "OCR",
    "expected": ["0/\\d+"],
    "roi": [850, 1280, 220, 50],
    "color_filter": "AutoSky_GreenCheck",  // ← 只在绿色区域 OCR
    "action": "DoNothing"
}

取色技巧(用截图工具):

  • 目标区域:取目标装饰/边框色(非文字色,文字一般会变色)
  • RGB 范围要宽松一些(±20),覆盖光照变化
  • method=4 是 RGB(0=HSV)

实战案例:本项目(MaaGumballs)用这个方法区分"能量条 0/31"vs"节点数 0/23",两者都是绿色 OCR 文本,周围装饰色也不同。

已验证:可滚动 UI 统一 ROI(10 城堡建筑)

节点统一 ROIscore备注
CastleManage[100, 400, 520, 880]0.999顶部
Market同上0.999顶部
Blacksmith同上0.998顶部
AlchemyWorkshop同上0.999顶部
TrainingCenter同上1.000顶部
CastleMainHall同上0.876顶部只露 25px
Shrine同上0.999中段
Family同上0.999中段
Museum同上0.999底部
Manor同上0.999底部

关键设计

  • 所有节点 ROI 完全相同([100, 400, 520, 880],覆盖 y=400-1280)
  • 不靠 expand 微调,靠 expected 文字差异让 OCR 区分
  • 不放 next 链(避免死循环)

跨页面状态机流程(用 next + [JumpBack]

当生成的活动流程需要跨多个页面跳转(如:大地图 → 活动入口 → 难度选择 → 队伍 → 战斗),用 MaaFramework 的 next + [JumpBack] 机制串接各页面节点,不要写 Python orchestration

模式:状态机入口节点

{
    "MyActivity_Start": {
        "next": [
            "MyActivity_TeamReady",                      // 已在队伍配置页 → 点击"进入战斗"
            "[JumpBack]MyActivity_Difficulty_Select",     // 在难度选择页 → 选难度
            "[JumpBack]MyActivity_Enter"                 // 在大地图 → 找入口
        ],
        "timeout": 10000
    },

    "MyActivity_Enter": {
        "next": [
            "MyActivity_Enter_Click",                    // 找到图标 → 点击
            "[JumpBack]BigMap_Activity_Resident",         // 切"常驻"tab
            "[JumpBack]BigMap_Activity"                  // 打开活动页
        ],
        "timeout": 10000
    },

    "MyActivity_EnterBattle": {
        "recognition": "OCR",
        "expected": ["进入战斗"],
        "action": "Click",
        "next": [
            "MyActivity_FightStart",                       // 战斗开始
            "[JumpBack]MyActivity_TravelSelect_Boat",      // 乘船
            "[JumpBack]MyActivity_TravelSelect_Walk"       // 步行 fallback
        ]
    },

    "MyActivity_TravelSelect_Boat": {
        "recognition": "OCR",
        "expected": ["确定"],
        "roi": [490, 740, 100, 80],                     // 窄 ROI 限定乘船行
        "action": "Click"
    },

    "MyActivity_TravelSelect_Walk": {
        "recognition": "OCR",
        "expected": ["确定"],
        "roi": [490, 590, 100, 80],                     // 窄 ROI 限定步行行
        "action": "Click"
    }
}

关键设计要点

  1. [JumpBack] 是状态回退的关键:命中后执行完节点链,自动返回父节点的 next 继续。
  2. 窄 ROI 区分同名字段:用 y 范围 [490, 740, 100, 80] vs [490, 590, 100, 80] 区分两个"确定"按钮行(y 范围不重叠)。
  3. target_offset 偏移点击:识别难度文字后用 target_offset: [270, 0, 0, 0] 把点击位置右移到"确定

Content truncated.

When not to use it

  • When using a `Click` node's `next` for `[JumpBack]CastleSwipeDown/Up` in scrollable UIs
  • When `ocr()` is called after `screencap()` from an external source

Limitations

  • Requires `maa-mcp` MCP service
  • Requires a connected ADB device

How it compares

This skill automates the creation and integration of MaaFramework Pipeline nodes from UI observations, providing a structured and tool-assisted approach to pipeline development compared to manual JSON editing.

Compared to similar skills

pipeline-generate side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
pipeline-generate (this skill)015dReviewAdvanced
pdf-processing-pro179moReviewIntermediate
python-repl64moReviewBeginner
math-router66moReviewBeginner

Try saying

Example prompts that trigger this skill in your AI assistant.

Search skills

Search the agent skills registry