SheetForge Web
SheetForge 提供一个配套的 Web 应用,位于 web.sheetforge.workers.dev。它把创作、验证与工作表反射带到了浏览器中——不需要 Unity,也不需要安装任何东西。
同一套核心,而不是另一份重新实现
这个 Web 应用把完全相同的 C# 核心源码——正是无头 .NET 测试工具所运行的那一份——编译为一个 .NET browser-wasm 程序集。不存在第二份解析器或验证器的副本,因此两者永远不会产生分歧:一条规则一旦被修复,两边都会同时被修复。
由这个设计直接引出两点。
- 你编译好的插件 DLL 可以原样加载,并且它们在这里点亮的是与编辑器中相同的插槽(见下文)。
- 本站上的表格语法规则,在浏览器中同样成立,且完全一致。 标记、类型系统、
@overlap、@style、@enum,@loc,以及引用完整性,行为方式完全相同,因为回答问题的正是同一份代码——这也包括IntId@Tab,LocRef@Tab的对等性,见表格语法。
一个插件,十二个插槽,两个宿主
一个插件不存在"Web 子集"这种东西。组装——实例化、排序、隔离,以及兼容性关卡——是一个纯粹的 Core 函数,两个宿主都会调用它。唯一不同的是发现方式:Unity 会索引项目中的类型,而浏览器则扫描你上传的程序集。
因此一个插件能够填充的十二个插槽,在两侧是完全相同的:
| 插槽 | 在浏览器中 |
|---|---|
| Enum · 单元格解析器 · 包装类型 | 单元格会通过你自己的记法进行解析、验证和往返 |
| 领域验证器 | 你的规则会与核心规则一起出现在 Problems 中 |
| 边贡献者 | 藏在你记法内部的链接会被画在画布上,并被计入引用索引 |
| 结构标记 | 你的 @marker 行会被接受并验证 |
| 工作表模板 | 你的模板会出现在创建工作表中 |
| 画布增强器 | 虚拟节点、额外的边、层级与显示提示 |
| 代码注册表 | 存在于代码中的键,不会再被画成损坏的引用 |
| 色彩预设 | 被映射到应用的 CSS 变量上 |
| 声明式 Studio UI | 你的动作、面板、列徽标和单元格编辑器提示,以 React 渲染 |
| UI 字符串 | 你的标签会跟随用户的语言,走的是与 t() 所查询的相同覆盖层 |
| 管线观察者 | 在一次导入周期结束时收到通知,与编辑器中完全一样 |
声明式界面正是一个插件的创作类扩展能够在这里存在的原因。一个会返回 UIToolkit 元素的契约永远无法在浏览器中加载,因此这里的外壳被描述为数据——一个 id、一个标签键、一个放置位置、一种色调——每个宿主再用自己的部件把它绘制出来。
当一个包需要的东西是这套词汇说不清楚的,它可以用同一个 id 注册一个仅限编辑器的富面板。编辑器会绘制那一个,浏览器则绘制那个描述性的版本,扩展永远不会就此凭空消失。
渲染时遵循两条规则:来自插件的文本会被转义,一个自绘制以来情况已经变化的动作,会给出一次如实的空操作,而不是对一个过期的 id 采取行动。
一个插件程序集还可以声明它是针对插件格式的哪一代构建的,以及它要求的最低宿主版本。如果它超出了这个宿主的可读范围,整个程序集都会被拒绝,并给出一条可读的原因,而不是被半加载。市场路径、旁加载路径,以及一个普通的本地文件,走的都是同一道关卡、读取的都是同一份声明。见插件开发。
什么依然留在 Unity 中
同样的诚实也适用于本地化:一张本地化表格可以在这里被完整地创作与验证,但同步 Unity Localization 的 StringTable 是编辑器的职责——浏览器没有可供写入表格的 Unity 项目。
代码生成与烘焙依然是仅限 Unity 的职责。浏览器无法生成 .cs 文件,也无法写入 ScriptableObject——它也从不假装能做到。凡是需要项目本身参与的东西,情况也是一样:资源选择器、从 Project 窗口进行的拖放,以及它们所暂存的 Addressables 注册,都只存在于编辑器中;AssetRef@Group<Type> 中的 <Type> 会在浏览器中被解析并显示出来,但只有在项目类型被加载的地方,它才会被真正解析出具体类型——并接受类型检查;而编辑器中资源的缩略图、放大预览与音频播放在 Web 端没有对应物,因为浏览器没有可供读取的项目资源——Web 网格中的一个资源单元格,呈现的只是它的地址文本。
Web 端的输出是反射后的工作表——经过验证、往返处理后的来源——而不是烘焙出的资源。你在浏览器中创作与验证,之后当你需要强类型的类和烘焙出的 SO 时,再到 Unity 中运行一次导入。无论哪种方式,工作表始终是唯一真实来源,因此两个界面最终都汇合于工作表本身。
Web 应用能做什么
一切都通过一份单一的 JSON 边界契约,与 WebAssembly 核心之间往返传递,因此浏览器 UI 永远不需要重新推导一条核心已经拥有的规则。
| 区域 | 你能获得什么 |
|---|---|
| 创作会话 | 导入、投影,以及一个由同一个导入验证器驱动的 Problems 面板——是预检诊断,而不是另一套独立的检查。导入功能既能接收 TSV 和 CSV 文件,也能接收 .xlsx 工作簿——工作簿中的每一张工作表都会作为独立的标签页到达,读取时使用的是与编辑器相同的读取器(编译为 WebAssembly);当有些内容需要被解读时——一个公式的缓存取值、一个被读作 yyyy-MM-dd 文本的日期、未被读取的格式——导入对话框会在一条**"How this workbook was read"**说明中如实说明。 |
| 表格编辑 | 按类型的单元格部件、撤销、列固定、排序、搜索、@style 分组与配色——外加编辑器已有的那套电子表格列功能集:拖动表头手柄可以设置一列的宽度(双击可自动调整;这个设置会按工作表保存在本浏览器中)、用字母与一条如实标出的边界线来隐藏与显示列、与搜索叠加的按列取值筛选,以及作为一步撤销的清除列数据。+ Row 会一次性暂存一行,并给出一个建议的键——整数 id 列会预先填好——可以直接在键单元格中重命名,没有键列的工作表则会禁用这个按钮并说明原因。Enum 与可选布尔单元格打开的是与引用单元格相同的可搜索选择器。并且任何时候都只会有一个选择器窗口保持打开:打开另一个会关闭上一个,点击别处或按 Esc 也会将其关闭。行号与列字母可以被选中(Ctrl 切换,Shift 选取范围),表头与表体会高亮显示选中的内容,被选中的单元格会画出一个跟随键盘操作的轮廓,而一个选择范围可以带着一条插入线被拖动到新的位置——一个不连续的选择会按照选中时的顺序,汇集在放下的位置,作为一步撤销;与此同时,右键菜单会把宽度、自动调整、隐藏、移动、删除和清除数据应用到每一个被选中的列(移动和删除则应用到每一个被选中的行),只对单个目标有意义的项目会单独归入它们自己的区块。枚举定义表拥有与数据表相同的列宽调整方式——拖动、双击自动调整、精确宽度、自动调整为适配数据、隐藏。超过 200 行后,网格只会渲染当前可见的窗口(外加预渲染余量),并用占位块撑住真实的滚动高度——这与编辑器表格使用的是同一个阈值,因此在一张大型工作表上,两者的手感是一致的。 |
| 视觉值 | Color、AnimationCurve 和 Gradient 单元格会显示一个铺满整个单元格的预览——一个色块、一条曲线折线、一条渐变条——并在一个弹出层中打开一个完整的编辑器:颜色编辑器带有一个 HSV 方形选择区、色相与 alpha 滑杆,以及一个十六进制输入框(浏览器原生的颜色输入控件没有 alpha 通道,因此没有使用它);曲线编辑器带有一个可缩放的网格、可拖动的关键帧与切线手柄、切线模式(Free、Auto、Linear、Constant、ClampedAuto——右键点击一个关键帧,或使用下拉选择)、断开与加权开关、数字输入框、前置/后置包裹,以及线性 / 渐入渐出 / 恒定预设;渐变编辑器带有可拖动的颜色关键帧与 alpha 关键帧(各至多 8 个)、一个模式选择框和一个颜色空间选择框。每一次更改都会经过 WebAssembly 核心往返处理——解析、切线重新计算与取样都是用 C# 完成的,而不是 JavaScript——提交的文本与编辑器写出的规范形式逐字节相同。更改会在你做出的那一刻立即提交,与编辑器的原生字段完全一样:编辑器打开期间,单元格、画布与 Problems 都会同步跟进,一次编辑会话无论产生多少次更改都会合并为一步撤销,重新打开编辑器则会开启新的一步。这里没有"应用"按钮——唯一的按钮是关闭(Esc 同样会关闭;在颜色编辑器中,Esc 还会把取值恢复到这次会话开始之前的样子);要撤回更改用 Ctrl+Z。不做任何更改就打开又关闭,不会暂存任何内容。一个可选列在为空时会显示 —,并在右键菜单中提供清除(默认);这三种类型的 List<> 是一个纸片列表,其新增 / 移除 / 重新排序 / 编辑手势各自都是一步撤销。预览条位于标准行高之内,与编辑器表格中一致。画布上的取值行使用的是相同的组件。 |
| 结构编辑 | 新增/删除/移动列,✎ 四字段列表单,标签页重命名(包括互换与循环重命名;xlsx 标签页会被阻止),工作表的创建/删除,以及一个活动设置下拉菜单——每一项都作为一步撤销被暂存。枚举定义表也以同样的方式创作——新增一个枚举、重命名(同一批次内重写每一个引用它的 @type)、删除、重排列,以及编辑基础类型与说明——遵循与编辑器相同的规则,因为判定所依据的是同一份代码。 |
| 跨表搜索 | 侧边栏的 All 条目会按部分匹配搜索每张工作表的 id 和字段取值,以工作表 · 键 · 字段 · 取值的形式列出结果,每页 50 行——匹配方式、排序和分页大小都与编辑器相同。它读取的是会话当前展示的取值,包括暂存的编辑在内,因此你刚改过的一个值会被立即找到。双击一条结果——或选中它并按下 Enter——对应的工作表就会打开并选中匹配到的单元格;由于搜索读取的是会话本身,每一条结果都可以被跳转到。 |
| 本地化 | 本地化表格在这里也是普通的工作表——包括创作、校验和按语言统计的覆盖率。数据表的 LocRef 单元格会内联显示该条目源语言的文本,并打开与其他引用相同的选择器;在一个空单元格中输入内容,会以一步撤销的方式铸造出键、其源语言文本和这个引用,与编辑器的做法完全一致。语言视图用于切换可见的语言列(仅影响显示),翻译工作簿会把选中的语言导出为 xlsx,并把返回的文件作为仅限语言列的合并再导入。同步 Unity Localization 的 StringTable 依然留在编辑器中。 |
| 记录画布 | 一条记录的素材与消费方都是卡片,你可以通过拖拽连线把它们连接起来——画布复用的是与编辑器完全相同的纯布局、连线与编辑链代码,因此像素级的运算存在于 C# 中,而不是某个 JS 图形库里。卡片展示的是与表格相同的投影:一列在这一批次中被暂存过的列,已经出现在卡片上并标记为"待处理",一次被暂存的重命名会在原有取值上方显示新名称,一次被暂存的删除也会把这一行从这里移除。 |
| 输出 | 按工作表下载的 TSV / CSV,一个把所有选中工作表都装进同一个文件的 .xlsx 工作簿下载(一个工作簿规则无法承载的工作表名称会被调整并报告,绝不会被静默改名),以及 Google表格 读写——每次推送后都会自动刷新工作表的数据验证下拉菜单(见下文)。 |
做到相同,而不只是相似
Web UI 与编辑器内的 Data Studio 是刻意对齐的,一路对齐到共享的逻辑本身。
- 共享的答案。 表头判定函数(
pending/edited)、差异对比弹窗,以及投影组合的顺序,都是共享的 C# 代码,因此两个界面对同一个问题给出的是同一个答案。 - 共享的句子。 当 Web 端镜像某个 Studio 界面时,它使用的是 Studio 自己的字符串键,其取值是在构建时从编辑器的语言表中生成出来的,而不是重新手打一遍。新增一句两个界面都会展示的话,只需要在
Lang*.cs中加一个键;分歧在结构上就不可能发生,而不仅仅是被约定所劝阻。有两样东西被刻意分开保管,一道构建期的守护检查会强制保证这条边界:- 真正仅限 Web 的字符串留在 Web 自己的目录中;
- 诊断信息与报告由 WebAssembly 核心渲染,而不会在 UI 中被重新措辞。
- 共享的观感。 图形和工作表被并排显示在一个可调整大小的分栏面板中,镜像了编辑器画布的钳制行为;每一种颜色都来自编辑器的
.aw-root令牌集这个唯一真实来源——没有硬编码的调色板。 - 共享的组件套件。 这套 UI 构建在一个内部的
aw套件之上,它的类名、令牌和弹出层定位方式,与编辑器的 USS 以及那份权威的 HTML 模型一一对应。现在是一份模型同时供给两个端口——Web 应用与 UIToolkit 编辑器——而不是让 Web 端各自独立漂移。web/Docs/ui-parity.md记录了当 Studio 发生变化时,Web 端应该如何跟进。 - 共享的单元格编辑器。 一个单元格得到哪种部件,是由核心的单元格编辑器 hint 决定的——先是插件包自己的注册,然后是内置表(
BuiltinCellEditorHints)——因此一个声明了ColorPicker、CurveEditor或GradientEditor形态的插件类型,在这里打开的编辑器与它在 Unity 中打开的完全相同,两个宿主环境不可能为同一个类型名选出不同的部件。 - 画布对等。 拖放操作已经与编辑器达到了完全对等:中键拖动或 Alt 拖动平移、空白处的级联菜单、连线与节点检查器、被拿起的连线的重影效果,以及带确认对话框的终点节点删除。缩放范围与编辑器一致(25%–200%),卡片的度量数据来自核心,而不是 JavaScript 里的另一份副本。
- 共享的类型列表。
@type下拉菜单提供的是解析器注册表实际知道的内容,分组方式与编辑器完全一致:内置标量(包括Color、AnimationCurve和Gradient)、RecordId/IntId键、RecordId@Tab与IntId@Tab引用、Enum<…>、AssetRef@Group,以及任何已加载插件注册的类型或包装类型。因此一个注册了新类型的插件,无需任何 Web 端改动就会出现在浏览器中。(在 WebAssembly 核心完成启动之前,最初的那一次绘制会回退到四种内置标量。)
该用哪一个
- 想要随时随地快速创作、验证与编辑工作表,或者团队中不打开 Unity 的成员,请使用浏览器。
- 当你需要生成的 C# 类和烘焙出的 ScriptableObject——也就是导入、代码生成和烘焙这几个步骤——请使用 Unity。
两者写入的是同一张工作表,因此在其中一端做出的更改,会在下一次读取时被另一端读到。
相关页面
- 表格语法——浏览器核心所强制执行的规则,与本站描述的完全一致
- 本地化表格——浏览器与编辑器中的游戏文本工作表
- Web 插件市场——在浏览器中安装与旁加载插件
- Web Google表格访问——从已部署的站点读写工作表
- Data Studio——Web 应用所镜像的那个编辑器内创作界面