TiXL 操作符创建实战指南:从 Symbol Browser 快速上手到手动测试集解读
【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3
本文以仓库
.tests-manual/creating-operators.md手动测试集为骨架,结合.tests-manual/README.md的格式规范、Editor/Gui/Graph/Legacy/Interaction/SymbolBrowser.cs与Operators/Lib/Symbols/image/generate/basic/RadialGradient.cs的源码实现,系统讲解 TiXL(实时动态图形创作工具)中最核心、最高频的操作——在 Graph Window 中创建操作符,并深入解读这份"测试即教程"文档的编写约定与底层原理。读完本文,你既能独立完成"打开 Symbol Browser → 搜索 → 放置"的完整创建流程,也能理解其背后的搜索过滤、实例化机制与手动测试集的撰写规则。
文档定位:一份"可执行"的操作符创建测试集
creating-operators.md位于 .tests-manual/ 目录,属于 TiXL 仓库中面向人工运行的验证流程(Manual Test Sets)之一。如 .tests-manual/README.md 所述,每个文件定义一个test set(测试集)——一组有序的steps(步骤),用于验证某个功能或流程。它们以纯 Markdown 书写,任何贡献者无需工具即可跟随执行;同时 frontmatter(文件头元数据)采用结构化字段,为未来"编辑器内运行器"(in-editor runner)的解析与驱动预留了接口。
该测试集自身的 frontmatter 信息如下:
| 字段 | 值 | 含义 |
|---|---|---|
id | creating-operators | kebab-case 唯一标识,与文件名一致 |
title | Creating Operators | 人类可读标题,将显示在运行器 UI 中 |
added | 2026-04-19 | ISO 日期,驱动"Recently added"排序 |
added-in-version | 4.2 | 该测试集首次随 TiXL 4.2 版本发布 |
scope | graph-window | 宽泛的功能区域标签 |
tags | [user, smoke, essential] | 运行器过滤用的标签 |
prerequisites | 空项目已打开、Graph Window 可见 | 执行前的准备条件 |
related-help | ../.help/using/graph-window.md | 指向用户文档的深入阅读链接(本文以仓库实际存在的文档重新组织) |
文档开头还有一段关键自述:"This is the move you'll make more than any other in TiXL"——添加操作符是你在 TiXL 中做得最多的一件事。这也解释了为什么该测试集被打上smoke(每次构建都运行的冒烟测试)与essential(功能主路径)标签。
前置条件
在执行本测试集之前,需要满足:
- 一个空项目已经打开(An empty project is open);
- Graph Window 可见(The Graph Window is visible)。
这两条保证测试者从一个干净、确定的初始状态出发,避免选中节点、已有布局等因素干扰后续断言。
步骤一:打开 Symbol Browser
操作(Action):在 [Graph Window] 获得焦点的情况下,按下Tab键。
预期结果(Expected):
- [Symbol Browser](符号浏览器)打开;
- 其搜索框已聚焦且为空——你可以立即开始输入。
源码佐证:Tab 触发与 Symbol Browser 的定位
从键盘层面看,.help/docs/using/KeyboardShortcuts.md 的默认快捷键表中明确列出:
| 动作 | 按键 |
|---|---|
| Add New Operator(添加新操作符) | Tab(Context search type name) |
也就是说,Tab 键被绑定为"添加新操作符"的全局触发键。在源码层面,Editor/Gui/Graph/Legacy/Interaction/SymbolBrowser.cs 的Draw()方法中可以看到其触发逻辑:
if (!IsOpen) { var hasFocus = ImGui.IsWindowFocused(ImGuiFocusedFlags.ChildWindows); var anythingActive = ImGui.IsAnyItemActive(); if (!hasFocus || anythingActive || !ImGui.IsKeyReleased(Key.Tab.ToImGuiKey())) return; ... ConnectionMaker.StartOperation(_graphView, "Add operator"); var screenPos = ImGui.GetIO().MousePos + new Vector2(-4, -20); var canvasPosition = canvas.InverseTransformPositionFloat(screenPos); OpenAt(canvasPosition, null, null, false); }这段代码揭示了几个实现细节:
- 仅在窗口未打开时响应 Tab:
IsOpen为 false 时才进入判断; - 需要 Graph Window 处于焦点:
ImGui.IsWindowFocused与IsAnyItemActive保证了"Graph Window 聚焦时"这一前置条件; - 在鼠标位置附近创建浏览器:通过
ImGui.GetIO().MousePos取得鼠标屏幕坐标,再逆变换为画布坐标,调用OpenAt(...)在鼠标位置打开 Symbol Browser; - 它本质上是 T2 时代 CreateOperatorWindow 的延续:类的注释明确指出它是
GraphView上新节点的占位符,具备搜索功能,可连接到其他节点。
此外,OpenAt()(SymbolBrowser.cs)还会做边界处理:如果浏览器打开位置太靠近画布边缘,会自动平移画布(FitAreaOnCanvas),避免浏览器被挤出可视区域——这就是测试中"Graph Window 可见即可稳定复现"的保证之一。
步骤二:按名称查找操作符
操作(Action):在 Symbol Browser 打开的状态下,输入RG(搜索是大小写不敏感的,且支持部分名称匹配)。
预期结果(Expected):
- 结果列表被过滤为名称中包含这些字母的操作符;
[RadialGradient]出现在列表中。
过滤机制的源码视角
Symbol Browser 的过滤逻辑围绕一个内部_filter对象展开。从OpenAt()(SymbolBrowser.cs)可见其关键状态:
_filter.FilterInputType = filterInputType; _filter.FilterOutputType = filterOutputType; _filter.SearchString = startingSearchString; _filter.OnlyMultiInputs = onlyMultiInputs; _filter.UpdateIfNecessary(_components.NodeSelection, forceUpdate: true);也就是说,浏览器在打开时不仅接受纯文本搜索串,还能按输入类型、输出类型、是否仅多输入进行过滤——这为从某个已有节点的输出端口拖出连线时自动筛选"可连接的运算符"提供了支撑(连接模式下会调用ConnectionMaker.StartOperation以"Add operator"命名)。
对于本测试集关心的"按名称搜索",文档明确声明的行为是:大小写不敏感 + 部分名称匹配。因此输入RG可以命中RadialGradient,rg同样可以。
为什么是 RadialGradient?
RadialGradient是仓库内置的标准图像生成操作符,源码位于 Operators/Lib/Symbols/image/generate/basic/RadialGradient.cs。该类继承自Instance<RadialGradient>,通过 GUID 特性标注唯一标识:
[Guid("82ad8911-c930-4851-803d-3f24422445bc")] internal sealed class RadialGradient : Instance<RadialGradient> { [Output(Guid = "9785937a-2b8f-4b2e-92ac-98ec067a40f2")] public readonly Slot<Texture2D> TextureOutput = new(); [Input(Guid = "54bca43c-fc2b-4a40-b991-8b76e35eee01")] public readonly InputSlot<T3.Core.DataTypes.Texture2D> Image = new InputSlot<T3.Core.DataTypes.Texture2D>(); ... }这展示了 TiXL 操作符的典型结构:InputSlot<T>声明输入(Image、Gradient、Width、Stretch、Offset、Center、Noise、BlendMode、Resolution 等),Slot<T>声明输出(TextureOutput)。每个输入输出都带有一个全局唯一的 GUID——如 .help/docs/getting-started/Concepts.md 所解释的,TiXL 大量使用 GUID 在对象之间建立引用,这使得重命名符号或参数不会破坏任何既有连接。
选择 RadialGradient 作为测试目标并非偶然:它的名称足够独特(输入RG即可命中),且在基础图像生成(image/generate/basic)命名空间中,是新用户最可能实际用到的操作符之一。
步骤三:创建操作符
操作(Action):在搜索结果可见的情况下,用上/下方向键高亮[RadialGradient],然后:
- 按
Return(回车),或 - 用鼠标点击该条目
将其放置到图上。
预期结果(Expected):
- 一个
[RadialGradient]操作符出现在图中光标位置; - 新操作符处于选中状态;
- 其输入显示在Parameter Window(参数窗口)中;
- Symbol Browser自动关闭。
一次操作引发的连锁状态变化
这一步骤验证了四个可观察结果,恰好对应创建操作的完整生命周期:
- 放置位置:
OpenAt(positionOnCanvas, ...)记录PosOnCanvas,新节点将出现在调用Tab时鼠标所在的光标位置; - 选中状态:创建后节点自动成为当前选择,
_selectedSymbolUi被设置为匹配列表首项(见 SymbolBrowser.cs); - 参数窗口联动:选中节点后,其输入槽(如 RadialGradient 的 Gradient、Center、Noise 等)随之在 Parameter Window 中显示,用户可立即调整;
- 浏览器关闭:放置成功后
IsOpen被置回 false,搜索界面退场,焦点交还画布。
文档建议"优先使用键盘触发而非鼠标拖拽"(见.tests-manual/README.md的 Authoring tips),因为键盘描述更无歧义、更易复现——这也是本步骤把方向键 + Return 作为主路径、鼠标点击作为并行备选的原因。
理解 TiXL 的核心概念:Operator / Symbol / Instance
创建操作符之所以是"用得最多的动作",是因为Operator 是 TiXL 中一切的中心构建块。按 .help/docs/getting-started/Concepts.md 的说明:
- Operator(操作符)——一切的核心构建块;
- 在描述"这个东西是什么"时,常被称为Symbol(符号)——Symbol 定义了操作符,包括子操作符实例及其参数、实例之间的连接、输入输出定义、描述、动画等;
- 在讨论"某个符号在另一个操作符内部的使用"时,常被称为Instance(实例)——实例的参数决定了符号如何被使用。
关键特性:
- 可嵌套:操作符可以包含其他操作符;
- 可复用:修改一个 Symbol 后,其所有实例立即更新;
- 可生成代码:操作符可以创建代码(如 Shader);
- 在视觉编程社区中,"ops"、"nodes"、"patches" 都是 Operator 的同义词。
而操作符的命名也暗含约束:因为操作符标题在内部被用作 C# 类名,所以不能包含空格或特殊字符、不能以数字开头(如MyFirstDemo✔、My Demo✘、1stProject✘)。你通过 Symbol Browser 搜索到的每一个名字,背后都是一个经过合法命名的 C# 类——这正是上面RadialGradient源码中internal sealed class RadialGradient : Instance<RadialGradient>的形式。注意其命名空间Lib.image.generate.basic遵循 Concepts.md 的规范:层级用.分隔、以小写字母开头、无空格与特殊字符——命名空间决定了操作符在 TiXL 操作符库中的存储位置,以及 AppMenu → Add 中的分组方式。
手动测试集的编写规范:一份可机器解析的 Markdown
理解这份文档的"怎么读",还要理解它"怎么写"。.tests-manual/README.md提供了完整的格式约定,这也是creating-operators.md结构之所以如此的原因:
frontmatter 字段约定
| 字段 | 必填 | 说明 |
|---|---|---|
id | ✅ | kebab-case、唯一、与文件名一致 |
title | ✅ | 人类可读标题,显示在运行器 UI |
scope | 建议 | 宽泛功能区域(自由标签) |
tags | 可选 | 供运行器过滤 |
added | 新集合必填 | ISO 日期(YYYY-MM-DD),驱动"Recently added"排序 |
added-in-version | 新集合必填 | 首次随附的 TiXLmajor.minor(如4.2) |
prerequisites | 可选 | 自由文本的准备条件 |
related-help | 可选 | 指向.help/的深入阅读相对链接 |
Step 结构约定
- 每个步骤以
## Step: <简短祈使句标题>开头;标题将显示为运行器副标题(如 "Step 3/12 — Creating an operator"),因此应写成被验证的事情,而非按键本身; **Action:**—— 给测试者的操作指令,用引导新用户的散文语气书写,如 "With the search results visible, use the cursor up/down keys to highlight[RadialGradient].";仅当步骤真正并行时才用项目符号(如"要么点击、要么按 Enter"),避免逐按键列点导致像清单而非导览;**Expected:**—— 用现在时书写、只写可观察结果;每条独立断言可用项目符号;禁止"should probably"式模糊表述——结果模糊就拆分步骤;**Context:**(可选,遗留字段)——一句话交代测试者所处状态;新集合应把上下文折叠进**Action:**的首句,运行器为兼容旧集仍会解析该字段。
标签词汇表与受众
标签虽是自由形式,但规范建议统一使用短核心词汇,便于运行器提供合理过滤:
smoke—— 60 秒以内,每次构建都运行;essential—— 功能的主要快乐路径;edge—— 边界情况、回归网络;perf—— 对性能敏感的观察步骤;flaky—— 已知间歇性失败的测试,修复前保留。
每个测试集还必须恰好携带一个受众标签:
user—— 艺术家验证自己在 TiXL 中真正会做的事(加载项目、设置音源、录制、导出),用平实语言、以屏幕所见命名,而非背后的文件/格式/类;dev—— 贡献者验证编辑器内部或构建工作流(创建操作符、图编辑的撤销/重做、构建失败消息等),保留技术细节。
creating-operators.md的标签为[user, smoke, essential],说明它被归类为"艺术家也能完成的、每次构建必跑的冒烟级主路径"。有趣的是,README 举例时把"creating operators"列为dev的典型场景,而本测试集选择了user视角——判定标准是"谁来运行它":只要非编程背景的艺术家能照着跑完,就归为user。
运行结果如何记录
测试集文件本身不存储每步结果。运行时可记录的结果为pass/fail/other(可附带自由文本评论),这些结果属于某一次运行而非测试定义本身——因此创建操作符这样的测试可以被反复执行,而不污染定义文件。
何时添加或更新测试集
README 明确规定了一条与.help/一致的项目规则:任何改动用户可见 UI 或行为的 PR,必须在同一 PR 内扩展现有测试集或新增一个。功能计划(.agentic/Plans/)应链接到对应测试集而不是复制步骤;被覆盖功能移除时,陈旧测试也随之删除。
写作技巧方面,规范还强调:
- 为从未用过 TiXL 的人写作——明确命名菜单、按钮与窗口;
- 每个步骤只做一个可观察变化,需要检查两件不相关的事就拆成两步;
- 避免绝对坐标("点击 200,400"),改用名称(Graph Window、Parameter Window、
[RadialGradient]); - 键盘触发优先于鼠标拖拽(更易无歧义描述);
- 若步骤依赖先前状态,需在
**Context:**中说明——因为运行器支持部分运行时,步骤不一定会从头到尾执行。
从"放置操作符"到"深入使用":延伸阅读路径
完成创建只是起点。围绕creating-operators.md验证的流程,仓库还提供了大量可直接继续深入的材料:
- 概念基础:.help/docs/getting-started/Concepts.md —— Operator/Symbol/Instance、命名规范、命名空间、GUID、界面配色语义(橙色=时间相关、蓝色=驱动/链接、绿色=快照可控、品红=需注意);
- 快捷键全景:.help/docs/using/KeyboardShortcuts.md —— Tab 之外的播放控制(J/K/L)、撤销重做(Ctrl+Z / Ctrl+Shift+Z)、复制粘贴、书签、布局等;
- 同类测试集:创建操作符之后,紧随其后的典型操作链都有对应测试集,例如 .tests-manual/undo-redo-graph-edits.md(图编辑撤销/重做)、.tests-manual/duplicate-with-connections.md(带连接复制)、.tests-manual/graph-sections.md(图分区)——它们共同构成了 TiXL 图编辑工作流的人工回归网络;
- 手动测试集总览:.tests-manual/README.md —— 完整格式规范、标签约定与维护流程。
小结
creating-operators.md虽然只有三个步骤,却精准覆盖了 TiXL 最高频操作——创建操作符——的完整链路:Tab唤起 Symbol Browser、输入部分名称(大小写不敏感)过滤、方向键 + 回车放置、参数窗口联动、浏览器自动关闭。将其与 SymbolBrowser.cs 的触发与过滤逻辑、RadialGradient.cs 的类结构、.tests-manual/README.md 的格式规范对照阅读,既能让你快速上手 TiXL 的核心交互,也能理解这份"测试即文档"是如何被设计为既可供新人跟随、又可供未来运行器解析的双重身份。
【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考