44 KiB
LinuxCNC AXIS 完全对标规范与执行计划
文档状态:执行基线 v1.0(源程序已冻结;实现和验收按任务逐项关闭)
适用版本:LinuxCNC 2.10.0~pre0 239dcf4284762ad7e9c65d390bc5524d855c2f8e
项目上下文:linuxcnc-2.10.0-pre0-wasm-m1-py-c1
主入口:web/react
原始 AXIS 入口:linuxcnc/share/axis/tcl/axis.tcl
配套通信契约:前端与通信详细设计
配套案例契约:案例对标计划
本文件是“Web 主界面完全对标 LinuxCNC 原始 AXIS”的唯一执行规范。它把原始 AXIS 的功能、界面结构、状态门控、快捷键、图标、绘图和外部集成拆成可追溯任务;没有来源、命令序列、状态结果和验收证据的功能,不得标记为完成。
1. 目标、定义和边界
1.1 对标目标
对标不是把网页做成相似的深色控制台,而是对同一配置、同一程序、同一输入序列满足以下四类等价:
- 结构等价:菜单、工具栏顺序、Notebook、程序区、DRO、状态栏、控制件和图标的角色与布局对应 AXIS。
- 操作等价:同一用户动作发出同一 LinuxCNC 语义命令,按相同状态条件启用、禁用、暂停、恢复或拒绝。
- 状态等价:任务态、解释器态、模式、轴/关节选择、位置显示、倍率、主轴、工具、冷却、报警和恢复结果来自同一权威状态,事件顺序和当前行一致。
- 结果等价:native AXIS oracle 与 WASM/Worker 的 command trace、tick、快照、事件、错误和 checkpoint 哈希一致;允许的浮点误差必须在功能条目中明确,不能事后放宽。
1.2 规范性术语
| 词 | 含义 |
|---|---|
| MUST | 必须满足,否则该条目失败 |
| MUST NOT | 严禁发生,否则停止验收 |
| SHOULD | 默认要求;若不满足必须记录理由和影响 |
| source oracle | 锁定 LinuxCNC 源码、原始 AXIS 运行或其确定性输出 |
| Web-equivalent | 浏览器中实现相同工作流和状态语义的等价控件,不复制桌面窗口进程 |
| host boundary | 原始程序依赖宿主进程、动态库、真实设备或外部窗口的边界;必须显式显示为 blocked/excluded |
| verified | 代码、测试、native/WASM/Worker 证据、视觉证据和自哈希报告均通过 |
| blocked | 输入、官方 oracle、浏览器能力或宿主边界不足;保留失败样本,不得伪造 verified |
1.3 明确边界
- LinuxCNC 原始 AXIS 是 Tk 前端;Web 采用 React/TypeScript/Worker/Three.js,实现的是 Web-equivalent,不是复制 Tk 窗口或在浏览器启动桌面进程。
exec classicladder、halshow、halmeter、halscope、linuxcnctop、debuglevel、外部编辑器、真实硬件和原始 socket 不得伪装为浏览器已支持;用 Web 面板或HOST_BOUNDARY诊断替代。- WASM、HAL、IO、Python、OPFS 和快照的权威状态在 Dedicated Worker;React 只能通过协议读写,不得访问 WASM 指针或直接写 OPFS。
- 原始图标必须使用锁定源码中的字节;重新绘制、emoji、通用 icon 库或不同来源的同名图标不算对标。
- 所有视觉结论必须在固定视口、固定字体/缩放和固定资源哈希下产生;动态 canvas 区域单独做像素/非空检查,不得用“截图看起来差不多”替代 DOM 和行为检查。
2. 锁定的 AXIS 源程序和证据入口
2.1 源文件分工
| 领域 | 原始来源 | 对标内容 |
|---|---|---|
| 主窗口、菜单、工具栏、Notebook、控件门控 | share/axis/tcl/axis.tcl |
全部主界面结构、动作、启用条件、快捷键和默认变量 |
| 图标加载、动态帮助、控件辅助函数 | share/axis/tcl/support.tcl、accel.tcl |
资源解析、tooltip、菜单/控件 accelerator |
| 自定义下拉、滚动条、对话框 | share/axis/tcl/combobox.tcl、sb.tcl、dialog.tcl |
Jog increment、MDI history、文件和错误对话框的交互语义 |
| AXIS 设计说明 | src/emc/usr_intf/axis/README |
AXIS 的定位是 file preview + live plot;自解释控件、tooltip 和 Quick Reference |
| 3D/预览窗口 | lib/python/gremlin.py、gremlin_view.py |
视角、缩放、拖动/旋转、预览加载、live plot、当前行和绘图刷新 |
| G-code 绘图和坐标叠加 | lib/python/rs274/glcanon.py |
rapid、path、dwell、tool、origin、offset、extents、grid、limits、velocity、DTG |
| 配置声明和 GUI 家族 | configs/sim/axis |
DISPLAY=axis、PYVCP/GLADEVCP/NGCGUI/VisMach/外部脚本及资源闭包 |
| 原始 bitmap | share/axis/images |
AXIS logo、toolbar、spindle、标准报警图标、banner |
本文中的 axis.tcl:N-M 是 linuxcnc/share/axis/tcl/axis.tcl 的行号简写;gremlin.py 和 glcanon.py 同理分别指上表中的完整路径。
2.2 源哈希和变更规则
基线文件的初始 SHA-256 记录如下;每次源更新必须重新生成 manifest 和本文件引用,不得沿用旧报告:
share/axis/tcl/axis.tcl c9f0b4dc686717b37565f85fb0ab8cc8ded9cfa0028cc0aaaccdbcf808c4c524
lib/python/gremlin.py 7559a52300de92ed156fe22267c8fbca975338321cf3afada141360a244756a3
lib/python/rs274/glcanon.py 0dfb20f1fdc05289894f3aa638357d98e1063fbd53329c723c777399ec7b33b7
src/emc/usr_intf/axis/README 2fe357ba28bb0aa66565f85fb0ab8cc8ded9cfa0028cc0aaaccdbcf808c4c524
若报告发现文件内容与上述哈希不一致,先修正文档/manifest,再开始实现。源码树中由运行时生成的 tool.tbl、sim.var、linuxcnc.var 必须标明是 source-owned 还是 runtime-generated-fixture,不可混用。
3. AXIS 原始功能完整清单
功能 ID 是后续任务、协议、测试和验收报告的稳定主键。每个 ID 至少绑定一条源码路径、一个 Web 控件、一个命令/查询、一个状态字段和一份 evidence。
3.1 应用壳、菜单和窗口
| ID | 原始功能 | 原始实现/行 | Web 对标要求 |
|---|---|---|---|
| AXIS-SHELL-01 | 窗口标题 AXIS <version> on <machine>,无文件时显示 (no file),有文件时显示文件名 |
axis.tcl:1755-1765 |
根据 Worker 的 machine/taskfile 快照更新标题;标题更新不能改变仿真状态 |
| AXIS-SHELL-02 | 顶级菜单 File、Machine、View、Help | axis.tcl:33-53,468-482 |
顺序、命名、子菜单、快捷键和 enabled 状态一致;菜单项必须有可测试的 data-axis-command |
| AXIS-SHELL-03 | 最小窗口尺寸随 pane 请求尺寸更新 | axis.tcl:2234-2240 |
CSS 使用稳定最小尺寸和滚动策略;窄屏切换布局,不能让高风险按钮被裁掉 |
| AXIS-SHELL-04 | About AXIS、Quick Reference 对话框 | axis.tcl:453-464,1549-1632 |
Web modal 保留版本、许可证、源码链接、快捷键和关闭/焦点语义;外部链接另标记 host/network boundary |
| AXIS-SHELL-05 | 动态帮助 tooltip | axis.tcl:2250-2270、accel.tcl:150-185 |
所有图标按钮的 tooltip 文案、快捷键和 disabled 原因可通过 DOM/辅助技术读取 |
3.2 File 菜单和工程入口
原始菜单定义位于 axis.tcl:55-102。Web 实现必须保留以下条目和顺序:
| ID | 菜单项 | 语义 |
|---|---|---|
| AXIS-FILE-01 | Open… (O) |
选择 G-code,解析、预览并进入 PROGRAM_LOAD; 不允许 basename 替换 |
| AXIS-FILE-02 | Recent Files | 最近文件列表、序号快捷键、清空列表;路径/哈希来自 Worker 工程存储 |
| AXIS-FILE-03 | Edit… | 以配置声明的 editor 或 Web G-code editor 打开;宿主 editor 必须显示 HOST_BOUNDARY |
| AXIS-FILE-04 | Reload (Ctrl-R) |
仅在解释器 idle 且有 taskfile 时启用;重新读取精确资源 |
| AXIS-FILE-05 | Save G-code as… (Ctrl-S) |
保存当前内容/版本,写 journal,返回文件哈希 |
| AXIS-FILE-06 | Properties… | 显示程序路径、大小、行数、解析诊断、单位和 source hash |
| AXIS-FILE-07 | Edit tool data… | Web tool table editor;原始 tooledit 外部窗口标为 boundary |
| AXIS-FILE-08 | Reload tool data | 重新加载工具表并显示 table hash、当前刀、prepared/pocket |
| AXIS-FILE-09 | Ladder Editor… | Web ClassicLadder 面板;无法运行宿主 editor 时不得静默忽略 |
| AXIS-FILE-10 | Quit | 浏览器不能关闭宿主窗口;显示“关闭标签页”提示并记录 WEB_EQUIVALENT |
3.3 Machine 菜单和任务控制
原始定义位于 axis.tcl:105-264。下列条目是 P0/P1,不得只保留 Run/Pause:
| ID | 功能 | 关键语义 |
|---|---|---|
| AXIS-MACHINE-01 | Toggle Emergency Stop (F1) |
ESTOP 状态机;急停时禁止运动/IO,界面进入 pressed/fault,恢复必须有独立 IO_RECOVER/reset 结果 |
| AXIS-MACHINE-02 | Toggle Machine Power (F2) |
task state OFF/ON;按钮 relief 与状态一致,不能把 recover 当作已上电 |
| AXIS-MACHINE-03 | Run program (R) |
仅 task ON、程序有效、解释器 idle 时启用;返回当前行、interp state、tick |
| AXIS-MACHINE-04 | Run from selected line | 以选中行建立确定性 seek/预读语义;没有选中行必须 disabled |
| AXIS-MACHINE-05 | Step (T) |
只执行下一行/下一 canonical 单元;记录 line before/after 和状态 hash |
| AXIS-MACHINE-06 | Pause (P) / Resume (S) |
只在对应 interp state 启用;pause 图标切换 tool_pause/resume_inhibit |
| AXIS-MACHINE-07 | Stop (Esc) |
中止程序而不是销毁 session;queue、tool、spindle、IO 和恢复点结果必须明确 |
| AXIS-MACHINE-08 | Stop at M1 | optional_stop checkbutton/toolbar relief 与 M1 行为一致 |
| AXIS-MACHINE-09 | Skip lines with / |
block_delete checkbutton/toolbar relief 与程序过滤语义一致 |
| AXIS-MACHINE-10 | MDI history clear/copy/paste | Ctrl-M、Ctrl-H、Ctrl-Shift-H;历史只在 Worker committed state 中更新 |
| AXIS-MACHINE-11 | Calibration | 原始 emccalib.tcl 是外部窗口;Web 提供能力诊断或 boundary,不得模拟完成 |
| AXIS-MACHINE-12 | Show HAL Configuration / HAL Meter / HAL Scope | 分别映射 HAL graph、HAL sample/plot、scope;原始外部窗口路径保留诊断 |
| AXIS-MACHINE-13 | Show LinuxCNC Status / Set Debug Level | 映射状态时间线、日志和 debug level 白名单;未经授权的 level 必须拒绝 |
| AXIS-MACHINE-14 | Homing / Unhoming | 动态子菜单按轴/关节生成;顺序、homed、limit、门控和错误一致 |
| AXIS-MACHINE-15 | Zero coordinate system | P1…P9/G54…G59.3/G92 全部入口;每次写入显示坐标系、旧值、新值和 hash |
| AXIS-MACHINE-16 | Tool touch off to workpiece/fixture | tto_g11 两种模式;选择影响 G10/G11 语义并在快照中可见 |
3.4 View 菜单、DRO 和坐标显示
原始定义位于 axis.tcl:266-449。View 菜单必须拆成可验证状态,不得只做文字菜单:
| ID | 功能 | 状态字段/输出 |
|---|---|---|
| AXIS-VIEW-01 | Top / Rotated Top / Side / Front / Perspective | view_type、camera pose、视角图标 relief;对应 set_view_z/z2/x/y/p |
| AXIS-VIEW-02 | Display Inches / Display MM | metric;DRO、速度、倍率单位同步;切换不改机床内部单位 |
| AXIS-VIEW-03 | Show program | program path overlay 开关 |
| AXIS-VIEW-04 | Show program rapids | rapid segments 是否显示 |
| AXIS-VIEW-05 | Alpha-blend program | program overlay alpha |
| AXIS-VIEW-06 | Show live plot | 已运行轨迹与预览轨迹分层;clear 不得删除程序预览 |
| AXIS-VIEW-07 | Show tool | tool cone/model、tool position、orientation |
| AXIS-VIEW-08 | Show extents | program/machine extents bounding box |
| AXIS-VIEW-09 | Grid Off/Custom | grid size、origin、spacing 和自定义参数 |
| AXIS-VIEW-10 | Show offsets | G5x/G92/tool offset 可视化和数值 |
| AXIS-VIEW-11 | Show machine limits | axis/joint limits overlay 和 limit fault |
| AXIS-VIEW-12 | Show velocity | velocity vector/数值;来源为 snapshot,不使用墙钟推算 |
| AXIS-VIEW-13 | Show distance to go | DTG 与 commanded/actual、machine/relative 模式联动 |
| AXIS-VIEW-14 | Large coordinate font | DRO 字号开关,布局必须稳定 |
| AXIS-VIEW-15 | Clear live plot (Ctrl-K) |
仅清 live layer,返回新 plot revision |
| AXIS-VIEW-16 | Show PyVCP panel (Ctrl-E) |
配置声明 PYVCP 时显示 Web VCP;缺少 host plugin 时显示 boundary |
| AXIS-VIEW-17 | Show commanded/actual position | display_type,DRO 与状态栏同源 |
| AXIS-VIEW-18 | Show machine/relative position | coord_type,DRO 与触碰/坐标系同源 |
| AXIS-VIEW-19 | Joint mode / World mode | teleop_mode;非平凡 kinematics 未全 homed 时禁止切换到 world |
3.5 AXIS 工具栏和图标对照表
原始工具栏从 axis.tcl:484-787 创建并按 671-787 顺序 pack。图标文件必须来自 linuxcnc/share/axis/images:
| 序号 | 原始 widget | 图标 | 原始动作 | Web 对标 |
|---|---|---|---|---|
| 1 | machine_estop |
tool_estop.gif |
estop_clicked |
icon-only button,tooltip Toggle Emergency Stop [F1] |
| 2 | machine_power |
tool_power.gif |
onoff_clicked |
task power 状态,初始 disabled/relief 与 oracle 一致 |
| 3 | file_open |
tool_open.gif |
open_file |
精确资源选择 + PROGRAM_LOAD |
| 4 | reload |
tool_reload.gif |
reload_file |
reload gate |
| 5 | program_run |
tool_run.gif |
task_run |
run gate |
| 6 | program_step |
tool_step.gif |
task_step |
step gate |
| 7 | program_pause |
tool_pause.gif / resume_inhibit.gif |
task_pauseresume |
pause/resume 图标切换 |
| 8 | program_stop |
tool_stop.gif |
task_stop |
stop/abort gate |
| 9 | program_blockdelete |
tool_blockdelete.gif |
toggle_block_delete |
pressed state + 程序语义 |
| 10 | program_optpause |
tool_optpause.gif |
toggle_optional_stop |
pressed state + M1 语义 |
| 11 | view_zoomin |
tool_zoomin.gif |
zoomin |
camera scale |
| 12 | view_zoomout |
tool_zoomout.gif |
zoomout |
camera scale |
| 13 | view_z |
tool_axis_z.gif |
set_view_z |
top camera |
| 14 | view_z2 |
tool_axis_z2.gif |
set_view_z2 |
rotated top camera |
| 15 | view_x |
tool_axis_x.gif |
set_view_x |
side camera |
| 16 | view_y |
tool_axis_y.gif |
set_view_y |
front camera |
| 17 | view_y2 |
tool_axis_y2.png |
set_view_y2 |
inverted front camera |
| 18 | view_p |
tool_axis_p.gif |
set_view_p |
perspective camera |
| 19 | rotate |
tool_rotate.gif |
toggle drag/rotate | pressed state and pointer gesture |
| 20 | clear_plot |
tool_clear.gif |
clear_live_plot |
live layer only |
验收必须检查:文件名、字节 hash、实际加载 URL、alt/tooltip、按钮顺序、disabled/pressed relief 和点击后的命令。QtVCP 同名镜像只能用于历史兼容,不得作为 AXIS source oracle。
3.6 Manual Control Notebook
原始布局在 axis.tcl:803-1213,默认页为 Manual Control [F3]:
| ID | 控件 | 必须保留的行为 |
|---|---|---|
| AXIS-MANUAL-01 | 轴选择 X/Y/Z/A/B/C/U/V/W | 3×3 radio;axis_activated;非平凡运动学切换为动态 joint numbers |
| AXIS-MANUAL-02 | Jog -/+ |
增量模式 click 一次;Continuous 模式 pointer/key down 开始、release/leave 必须 JOG_STOP |
| AXIS-MANUAL-03 | Jog increment | Continuous, 0.1000, 0.0100, 0.0010, 0.0001;选择变化进入命令 payload |
| AXIS-MANUAL-04 | Home Axis | 当前轴/关节 home;Home 键快捷键;结果更新 homed/limit/position |
| AXIS-MANUAL-05 | Touch Off | G54 当前轴;End 快捷键;保存坐标系结果 |
| AXIS-MANUAL-06 | Tool Touch Off | Ctrl-End;只在有加载工具且模式允许时启用 |
| AXIS-MANUAL-07 | Override Limits | 只在 on_any_limit 时启用;临时越限必须有 fault/recover trace |
| AXIS-MANUAL-08 | Spindle CCW/Stop/CW | spindledir radio、16×16 原始图标、F10/F9;Stop 文案必须可读 |
| AXIS-MANUAL-09 | Spindle -/+ | 按下加速/减速、释放进入 constant;F11/F12;主轴未运行时 disabled |
| AXIS-MANUAL-10 | Brake | B/Shift-B;状态和互锁可见 |
| AXIS-MANUAL-11 | Mist/Flood | F7/F8;冷却状态、故障和恢复来自 device IO |
| AXIS-MANUAL-12 | Jog Speed/Max Velocity | 来源为 jog_slider_val/maxvel_slider_val,单位随 metric,显示值和内部速度转换一致 |
3.7 MDI Notebook
原始布局在 axis.tcl:1215-1294:History listbox、MDI Command entry、Go 按钮。Web 必须支持:
- 历史最多/最少行为与 Worker 的
mdi_history一致,初始有空元素,不把草稿历史当已执行。 - Enter 与 Go 相同,发送
MDI_EXECUTE,返回 command result、当前行、模式和错误行。 queued_mdi_commands >= max_queued_mdi_commands时整个 MDI group disabled(axis.tcl:1851-1855)。Ctrl-M清历史,Ctrl-Hhistory→clipboard,Ctrl-Shift-Hclipboard→history;浏览器 clipboard 权限失败必须显式诊断。
3.8 Preview、DRO、程序和状态栏
原始布局在 axis.tcl:1296-1709:
| 区域 | 原始行为 | Web 必须实现 |
|---|---|---|
| Preview tab | Gremlin/GLCanon 预览、程序/rapid/live/tool/extents/offset/grid/limit/velocity overlays | Three.js/WebGL 只消费 Worker snapshot/trajectory;每层可独立开关,canvas 必须非空 |
| DRO tab | 原始 AXIS DRO widget;显示 machine/relative、actual/commanded、DTG、单位、关节态 | 表格列和模式可切换;数值、单位、homed、limit、fault、tick/hash 同源 |
.info.task_state |
ESTOP/OFF/ON,sunken relief | task_state 颜色/状态必须由快照驱动 |
.info.tool |
当前刀具/工具信息 | current/prepared/pocket/change state 和 tool table hash |
.info.position |
Position + coordinate type + display type | Machine/Relative 与 Actual/Commanded 组合准确 |
| G-code pane | 有滚动条、当前行/highlight、底部固定 pane | 编辑/选行/运行到选中行/错误定位;不能使用静态 <pre> 冒充 |
| Active G-Codes | gcodes text,disabled、2 行起步 |
modal codes、units、plane、feed/spindle/tool/coolant 同步 |
| Jog sliders | jogspeed、ajogspeed、maxvel,值通过 setval/val2vel 转换 |
显示值与内部单位、min/max、metric 切换、键盘增量一致 |
| Overrides | spinoverride、feedoverride、rapidoverride,0…120%、整数分辨率 |
worker authoritative override;滑块 release/commit 和 pending/error 可见 |
3.9 状态门控、默认状态和快捷键
axis.tcl:1715-1887 是行为对标的核心,不得只按按钮标签实现。门控规则:
ESTOP时 machine power、程序、jog、主轴、冷却等高风险动作禁用;estop relief 按下。- task 非 ON 时 manual group disabled;task ON 且 interpreter idle 时才 enable manual group。
- 有 taskfile 且 idle 才能 reload、edit、properties、open、block-delete;有 taskfile 且 ON 才能 step。
- interpreter reading/waiting 才能 Pause;paused 才能 Resume;非 idle 才能 Stop。
on_any_limit才能启用 Override Limits;非自由运动学或 identity kinematics 且 idle 才能 Touch Off。- 有有效工具、task ON、idle、模式允许时才能 Tool Touch Off。
- MDI queue 未满才启用 MDI group。
- 非平凡 kinematics 的自由/joint 模式显示 joint numbers;没有全 homed 不能从 joint 切换到 world。
默认变量见 axis.tcl:1941-1985,至少包含 rotate_mode、taskfile、task_state、task_mode、task_paused、optional_stop、block_delete、interp_pause、interp_state、running_line、highlight_line、coord_type、display_type、spindledir、motion_mode、kinematics_type、metric、queued_mdi_commands。Web store 必须有等价字段或明确映射,不能删除门控原因。
快捷键基线:
| 键 | 功能 | 来源 |
|---|---|---|
| F1/F2 | 急停/电源 | axis.tcl:105-113 |
| O/Ctrl-R/Ctrl-S | Open/Reload/Save | axis.tcl:55-76 |
| R/T/P/S/Esc | Run/Step/Pause/Resume/Stop | axis.tcl:117-144 |
| Ctrl-M/Ctrl-H/Ctrl-Shift-H | MDI history | axis.tcl:158-169 |
| Ctrl-K/Ctrl-E | Clear live plot/Show PyVCP | axis.tcl:378-387 |
| F3/F5 | Manual/MDI tab | axis.tcl:820-825 |
| Home/End/Ctrl-End | Home/Touch Off/Tool Touch Off | axis.tcl:2258-2260 |
| F7/F8/F9/F10/F11/F12 | Mist/Flood/Spindle/速度 | axis.tcl:2250-2257 |
| X/Y/Z/A/4/5 | 轴激活 | axis.tcl:2261-2266 |
| Ctrl-Tab | Manual/MDI 切换 | axis.tcl:1989-1996 |
4. LinuxCNC 源功能到 Web 实现的映射
4.1 分层映射原则
| 原始层 | Web 层 | 强制规则 |
|---|---|---|
| Tk widget/variable | React component + domain store | 控件可以换实现,字段名、启用条件、事件顺序不能换 |
| AXIS command procedure | protocol command | 每个副作用动作有 operation_id、pending/ack/result/error、tick/hash |
| LinuxCNC status/NML | Worker snapshot/event | UI 不可读取指针、共享内存或宿主 NML |
| Gremlin/GLCanon | Three.js visual workflow | 只读 pose/joints/toolpath/stock/overlay;渲染失败不能改变仿真 |
| Tcl external exec | Web panel or host boundary | 不可静默成功;必须有 capability result 和 source path |
| Tk image | exact bitmap URL | 记录字节 hash,禁止同名替换 |
state/relief |
disabled/aria-pressed/visual state |
状态由 authoritative snapshot 派生,不能由点击乐观设置 |
4.2 推荐组件和协议字段
AxisShell
├─ AxisMenuBar File / Machine / View / Help
├─ AxisToolbar exact source icons, order and tooltip
├─ AxisNotebook
│ ├─ ManualControl axis/joint, jog, home, touch-off, spindle, coolant
│ └─ MDIControl history, command, go, queue gate
├─ ViewNotebook
│ ├─ Preview Three.js/trajectory/overlays
│ └─ DRO machine/relative × actual/commanded × DTG
├─ ProgramPane source, line selection, current line, active G-codes
├─ OverridePane feed/rapid/spindle/jog/max velocity
└─ AxisInfoBar task state, tool, position, alarm/recovery
最低命令集合:PROGRAM_LOAD, PROGRAM_RUN, PROGRAM_SEEK, PROGRAM_STEP, PROGRAM_PAUSE, PROGRAM_RESUME, PROGRAM_ABORT, MDI_EXECUTE, JOG_START, JOG_STOP, HOME, SET_MODE, SET_OVERRIDE, SPINDLE_COMMAND, COOLANT_COMMAND, TOOL_PREPARE, TOOL_CHANGE, PROBE_CONFIG, ESTOP, IO_RECOVER, HAL_COMMAND, SNAPSHOT_REQUEST, CHECKPOINT, RECOVER。新增命令必须先更新 protocol capability、source map、replay fixture 和本规范任务表。
5. 严格对标流程
每个 AXIS 功能 ID 都必须独立走完以下流程;不允许把多个功能合并成一张“整体通过”截图。
R0:冻结基线
- 读取
context-lock.json、linuxcnc/VERSION和 source commit。 - 计算源文件、图标、配置入口、HAL、TBL/VAR、程序和生成资源 hash。
- 记录 OS、浏览器、DPR、viewport、字体、语言、单位和启动参数。
- 若输入有未提交 runtime fixture,先分类
source-owned/runtime-generated/user-approved-fixture。
退出条件:source manifest、asset manifest、case manifest、运行环境 JSON 均 self-hashed;否则 STOP。
R1:提取原始功能
- 从
axis.tcl的 menu/widget/proc/bind/state 定义生成axis-source-inventory.jsonl。 - 从
support.tcl、accel.tcl、gremlin.py、glcanon.py提取依赖动作、tooltip、视觉层和状态字段。 - 每个条目填写
feature_id,source_path,source_lines,source_hash,ui_role,command,state_fields,external_boundary。 - 把源代码中实际未实现/历史 wishlist 与当前功能分开,不把 wishlist 当现状。
退出条件:功能 ID 覆盖菜单、工具栏、Notebook、DRO、程序、状态、快捷键、图形和外部集成;任何未归属文件进入 audit 缺口。
R2:建立协议和状态契约
- 为每个命令定义输入 schema、能力条件、幂等键、成功结果、错误码和恢复语义。
- 为每个 UI 状态定义 authoritative snapshot 字段、派生选择器和 enabled predicate。
- 固定
pending → ack → result/error;ACK 不得被渲染为 verified。 - 录制最小 native trace:启动、加载、动作、step、快照、错误、恢复。
退出条件:同一操作可在 Worker replay 中重放;未定义的门控或错误不得进入 UI 实现。
R3:实现结构和图标
- 先实现 AXIS shell 和稳定布局,再接入动作;禁止用临时卡片替代原始区域。
- 按原始 pack 顺序加载 20 个 toolbar 图标,记录每个文件 byte hash、尺寸和 URL。
- 实现 File/Machine/View/Help 菜单和 Notebook;所有菜单 item 带稳定测试 ID。
- 对 canonical 1440×900、1280×800、390×844 截图并做 DOM geometry 检查。
退出条件:结构 diff 只剩有记录的字体/平台边界;工具栏顺序和 icon hash 100% 一致。
R4:实现控制和门控
- 先实现 ESTOP/OFF/ON/idle/reading/waiting/paused/limit/not-homed 状态转换。
- 再接 program/MDI/jog/home/touch-off/spindle/coolant/override。
- 每个 pointer/key 事件测试按下、移动、离开、释放、重复触发和 Worker 重启。
- 每个 disabled 状态测试“为什么 disabled”:UI 显示 source state、predicate 和 capability。
退出条件:状态矩阵的每一格都有 command trace 或明确 blocked 证据;没有基于本地 useState 的假成功。
R5:实现预览、DRO 和编辑器
- G-code load 后先产生解析/预览结果,再允许 run;程序预览、rapid、live plot、tool、offset、limits、grid 分层。
- DRO 实现 machine/relative、actual/commanded、DTG、unit、joint/world、large font。
- G-code editor 支持行号、当前行、高亮、选中行运行、错误列、滚动和程序 hash。
- 3D canvas 检查非空像素、有限坐标、视角、缩放、旋转和 resize;绘图线程不得改仿真 tick。
退出条件:同一 native/WASM trace 的当前行、DRO、path layer、tool pose、状态 hash 相同。
R6:案例和外部边界
minimal_xyz.ini:关闭 Cartesian P0 核心闭环。corexy_by_kins.ini与corexy_by_hal.ini:分别验证 kinematics/HAL 路径。- lathe、9-axis、gantry、nontrivial kinematics、iocontrolv2、vismach、PYVCP/GLADEVCP/NGCGUI 代表案例按 family 扩展。
- 每个 DISPLAY/插件声明都输出 Web capability、host boundary 和缺失资源;不能把外部 Python/Tk/动态 loader 当作浏览器已完成。
退出条件:每个案例有 exact resource graph、native startup、Worker startup、frontend mapping、差异和 self-hashed report。
R7:视觉、交互和故障验收
- DOM:区域、顺序、role、label、tooltip、快捷键、禁用/pressed、焦点顺序。
- Screenshot:canonical viewport 的结构区域、工具栏顺序、icon byte/尺寸、颜色/边框、文字和间距。
- Interaction:每个 command 的操作序列、pending/ack/result、错误和恢复。
- Fault:ESTOP、limit、following error、invalid G-code、HAL blocked、tool busy、OPFS quota、Worker crash/restart。
- Performance:首屏、Worker ready、snapshot latency、3D frame、stream backpressure、内存和长程序编辑器。
退出条件:报告包含失败截图/DOM/trace,而不是只有通过计数;任何 STOP 条件未关闭则 milestone 保持 blocked。
R8:发布门禁
source_hash,asset_hash,case_hash,command_trace_hash,endpoint_hash,screenshot_hash全部可复现。- native、WASM、Worker、React、浏览器矩阵版本和运行参数明确。
- host boundary、REAL-EXCLUDED、缺资源、官方 oracle 缺失和浏览器不支持分开统计。
- 不以“实现存在”“构建通过”替代行为或视觉验收。
- 报告自哈希失败、首个 divergent tick 未定位、恢复重复副作用、真实硬件误报或降低检查才能通过时立即
STOP_RELEASE。
6. 任务分解
任务状态初始为 planned。每个任务完成时必须提交代码、专属测试和 self-hashed evidence;依赖未完成不得跳过。
| 任务 ID | 任务 | 具体输出 | 依赖 | 专属验收 |
|---|---|---|---|---|
| AXIS-INV-01 | 冻结 AXIS 源 | source/version/environment manifest | 无 | R0 manifest hash |
| AXIS-INV-02 | 生成 Tcl UI inventory | menu/widget/proc/bind/state JSONL | INV-01 | 每行 source path/line/hash |
| AXIS-INV-03 | 生成 bitmap inventory | 20 toolbar + logo/spindle/std icon hash/size | INV-01 | byte hash、URL、尺寸一致 |
| AXIS-INV-04 | 生成 AXIS case inventory | configs/sim/axis exact graph + DISPLAY family |
INV-01 | 无 basename substitution |
| AXIS-CON-01 | 状态枚举契约 | task/interp/motion/mode/coordinate/override/device schema | INV-02 | reducer/state contract tests |
| AXIS-CON-02 | 命令和 ledger 契约 | command schema、idempotency、ack/result/error | CON-01 | duplicate/replay/cancel tests |
| AXIS-CON-03 | 门控谓词契约 | state()/relief() 的 Web selector |
CON-01 | 全状态矩阵覆盖 |
| AXIS-CON-04 | 诊断和 boundary 契约 | host/Python/loader/real hardware 分类 | CON-02 | blocked 不得伪造成功 |
| AXIS-UI-01 | AXIS shell | title、menu、main panes、responsive root | INV-02 | DOM geometry + screenshot |
| AXIS-UI-02 | File menu | Open/Recent/Edit/Reload/Save/Properties/tool/ladder/Quit | UI-01, CON-02 | menu order + command trace |
| AXIS-UI-03 | Machine menu | task controls、history、diagnostics、homing、offset、touch-off | UI-01, CON-03 | state-gated menu matrix |
| AXIS-UI-04 | View menu | views、units、overlays、DRO、grid、teleop | UI-01, CON-01 | setting round-trip + screenshot |
| AXIS-UI-05 | Exact toolbar | 20 icons、顺序、tooltip、pressed/disabled | INV-03, UI-01 | asset and DOM hash |
| AXIS-UI-06 | Notebook shell | Manual/MDI、Preview/DRO tabs,焦点/快捷键 | UI-01 | tab switching/no reinit |
| AXIS-UI-07 | Info/program panes | task/tool/position、G-code、active G-codes、scroll | UI-06, CON-01 | current-line/scroll tests |
| AXIS-CTRL-01 | ESTOP/power/recover | task/IO 状态机和视觉 relief | CON-02, CON-03 | ESTOP fault/recover trace |
| AXIS-CTRL-02 | Program controls | load/run/line-run/step/pause/resume/stop/restart | CTRL-01 | native vs Worker endpoint |
| AXIS-CTRL-03 | MDI | command、history、Go、clipboard、queue gate | CTRL-01 | queue-full/history tests |
| AXIS-CTRL-04 | Jog | axis/joint、continuous/increment、press/release/stop | CTRL-01 | release safety and replay |
| AXIS-CTRL-05 | Home/touch-off | home、G54、tool offset、override limits | CTRL-04 | homing/limit/offset oracle |
| AXIS-CTRL-06 | Spindle/coolant | direction、rpm delta、brake、mist/flood | CTRL-01 | IO/device result and fault |
| AXIS-CTRL-07 | Overrides | jog/axis/max velocity/feed/rapid/spindle、metric | CTRL-01 | conversion and range tests |
| AXIS-CTRL-08 | Keyboard map | F1/F2/F3/F5/R/T/P/S/Esc/O/Ctrl keys/F7-F12 | UI-06, CTRL-* | keyboard replay matrix |
| AXIS-VIEW-01 | Preview parser | G-code path、rapid、dwell、current line | CTRL-02 | preview hash/line mapping |
| AXIS-VIEW-02 | Camera | z/z2/x/y/y2/p、zoom、drag/rotate | UI-05, VIEW-01 | canvas nonblank + camera state |
| AXIS-VIEW-03 | Overlays | live/tool/extents/grid/offset/limits/velocity/DTG | VIEW-01 | per-layer toggle screenshots |
| AXIS-VIEW-04 | DRO | machine/relative × actual/commanded × DTG/units/font | CON-01, VIEW-01 | numeric endpoint parity |
| AXIS-EDIT-01 | G-code editor | line numbers、highlight、selection、error column | CTRL-02 | selected-line/run/error tests |
| AXIS-EDIT-02 | Tool table | edit/reload/current/prepared/pocket/hash | CTRL-06 | tool IO/native trace |
| AXIS-EDIT-03 | Config/resource UI | INI/HAL/TBL/VAR/include graph and diagnostics | INV-04 | exact-path report |
| AXIS-EXT-01 | HAL/PLC diagnostics | graph、pin、scope、ClassicLadder Web panels | CON-04 | virtual HAL/PLC replay |
| AXIS-EXT-02 | PyVCP/GLADEVCP/NGCGUI | descriptor→Web component、Python boundary | AXIS-EDIT-03 | capability and blocked cases |
| AXIS-CASE-01 | Minimal XYZ | native/WASM/Worker/frontend full controls | CTRL-, VIEW- | minimal-xyz report |
| AXIS-CASE-02 | CoreXY dual path | kins vs HAL path | CASE-01 | two independent reports |
| AXIS-CASE-03 | Lathe/9-axis/gantry | axis/joint/lathe variations | CASE-01 | case family matrix |
| AXIS-CASE-04 | VisMach/5-axis | pose/joint/tool orientation/model/stock | VIEW-02, CASE-01 | visual + kinematics report |
| AXIS-TEST-01 | DOM/accessibility | roles、labels、focus、tooltip、shortcut | UI-* | browser DOM report |
| AXIS-TEST-02 | Canonical visual | 1440×900、1280×800、390×844 screenshots | UI-05, VIEW-* | pixel/geometry report |
| AXIS-TEST-03 | Interaction replay | command/event/ack/error/recovery sequence | CTRL-, EDIT- | trace hash |
| AXIS-TEST-04 | Native/WASM parity | endpoint/tick/state/error/plot hash | CASE-* | differential report |
| AXIS-TEST-05 | Fault matrix | estop/limit/invalid/blocked/busy/quota/restart | CTRL-01, CON-04 | all failure samples retained |
| AXIS-TEST-06 | Browser/performance | Chromium/Firefox/Safari、WebGL、OPFS、worker | TEST-01..05 | matrix report; blocked explicit |
| AXIS-REL-01 | Evidence index | 每功能、任务、报告、hash、owner、date | TEST-* | self-hash + link audit |
| AXIS-REL-02 | Release gate | license/NOTICE、boundary、STOP_RELEASE 决策 | REL-01 | no unresolved P0/P1 |
7. 验收里程碑
里程碑是累积门槛;后一个里程碑不能覆盖前一个未关闭的失败。
M0:源基线冻结
目标:AXIS source/UI/asset/case inventory 可重复生成。
必须通过:AXIS-INV-01…04;全部源引用、行号、hash 有效;不存在未分类的外部依赖。
证据:coverage/axis-source-inventory.report.json(同一 self-hashed 报告包含 source/UI/asset/case inventory)。
失败即停止:源码提交、资源字节、案例资源或 fixture 变化未重新生成报告。
M1:像素和结构对标
目标:首屏结构与原始 AXIS 一致。
必须通过:AXIS-UI-01…07、AXIS-TEST-01/02。
硬门槛:菜单四项顺序;toolbar 20 个图标顺序/byte hash/tooltip;Manual/MDI 与 Preview/DRO tab;程序区、Active G-Codes、info bar;canonical 桌面和窄屏无重叠、无裁切。
当前 Chromium 结构证据:coverage/gui-browser-visual-fe-m4.report.json,报告哈希 0df7a7c9c663292bbf1f764946032fb4ba1b882b23532863569470c723401ae1;Firefox/Safari/OPFS 不随该授权切片关闭。
不计入通过:只截图而没有 DOM geometry、asset URL、aria/tooltip 检查。
M2:控制和状态门控对标
目标:每个按钮在与原始 AXIS 相同的状态下启用/禁用/pressed,并产生相同语义命令。 必须通过:AXIS-CON-01…04、AXIS-CTRL-01…08、AXIS-TEST-03/05。 硬门槛:ESTOP、OFF、ON、idle、reading、waiting、paused、limit、not-homed、queue-full 全矩阵;jog release safety;重复 operation 不产生副作用。 失败分类:首个 divergent command/tick、错误码、门控谓词和恢复状态必须定位。
M3:程序、MDI、DRO、预览对标
目标:G-code、MDI、程序预览、live plot、DRO、坐标/单位/模式全部对齐。 必须通过:AXIS-VIEW-01…04、AXIS-EDIT-01、AXIS-CASE-01、AXIS-TEST-04。 硬门槛:native/Worker 当前行、active G-codes、machine/relative、actual/commanded、DTG、metric、path layer、tool pose、state hash 一致;canvas 非空且切换视角不改变仿真结果。
M4:工具、HAL、插件和外部边界
目标:工具表、主轴/IO、HAL/PLC、PYVCP/GLADEVCP/NGCGUI/VisMach 入口可用或明确 blocked。 必须通过:AXIS-EDIT-02/03、AXIS-EXT-01/02、AXIS-CASE-02…04。 硬门槛:所有 host-only 能力有 capability/boundary 记录;不允许用 mock 让外部菜单显示 verified;HAL pin 类型、线程顺序和工具 IO 事件可回放。
M5:案例级 native/WASM/Worker/frontend parity
目标:代表案例及全量 AXIS 案例矩阵有 exact resource、startup、control、visual、recovery 证据。
必须通过:AXIS-TEST-04、案例对标计划 S8-03…S8-10。
硬门槛:每案例 endpoint/checkpoint/event hash 可重放;资源 blocker、host blocker、oracle blocker、error 分开;不能把 STATIC READY 当 TASK_READY。
M6:浏览器、性能和恢复
目标:支持矩阵下 UI/Worker/OPFS/3D/恢复可复现。 必须通过:AXIS-TEST-01…06。 硬门槛:Chromium canonical visual/performance/recovery verified;Firefox/Safari/OPFS 若环境不支持则保留 blocked 证据;Worker crash/restart、offline、quota、half-commit 不丢 journal、不重复副作用。
M7:发布关闭
目标:AXIS 对标交付有可审计证据和边界声明。 必须通过:AXIS-REL-01/02、所有 P0/P1 条目、所有 release gate。 禁止发布:视觉只验了 React 静态 DOM;native oracle 缺失未标记;浏览器矩阵未跑却宣称全平台;真实硬件/宿主能力被算作 Web 等价;报告无法自哈希。
8. 证据格式和差异判定
8.1 单功能 evidence schema
每个 feature_id 的报告至少包含:
{
"schema": "axis-feature-evidence.v1",
"feature_id": "AXIS-MANUAL-02",
"status": "verified",
"source": {
"path": "linuxcnc/share/axis/tcl/axis.tcl",
"lines": "893-924",
"sha256": "..."
},
"web": {
"paths": ["web/react/src/App.tsx", "web/react/src/worker-client.ts"],
"selectors": ["[data-axis-feature=AXIS-MANUAL-02]"],
"asset_urls": []
},
"protocol": {
"commands": ["JOG_START", "JOG_STOP"],
"operation_ids": ["..."],
"capability_predicate": "task=ON && interp=IDLE && !ESTOP"
},
"oracle": {
"native_trace_hash": "...",
"worker_trace_hash": "...",
"endpoint_hash": "...",
"first_divergent_tick": null
},
"visual": {
"viewport": "1440x900@1x",
"dom_hash": "...",
"screenshot_hash": "...",
"asset_hashes": []
},
"failure_policy": "blocked|host_boundary|missing_oracle|resource|error",
"report_sha256": "..."
}
8.2 差异判定顺序
出现差异时按以下顺序停止和定位:
- source/config/resource hash 是否相同;
- 启动 phase 和 capability 是否相同;
- command kind、payload、seq、operation_id 是否相同;
- 第一个不同的
simulation_tick、task/interp/motion state; - 事件顺序、错误码、alarm/recovery、checkpoint/event hash;
- 最后才比较 DOM geometry、样式和 canvas 像素。
不能先调 CSS 掩盖状态差异,也不能先放宽数值容差。数值容差应按来源类型登记:整数/枚举必须完全相等;位置/速度按固定浮点策略;哈希、事件序号、行号和命令序列不允许容差。
8.3 视觉判定
- 强等价:布局区域、菜单顺序、工具栏顺序、原始 icon byte、控件 role/label、状态颜色和 disabled/pressed 必须精确。
- 规范化等价:浏览器字体抗锯齿、滚动条、系统 checkbox 外观可在 report 中 mask,但区域尺寸、文本内容、边界和可访问名称不能 mask。
- 动态图层:Three.js canvas 进行 nonblank/finite/pixel sample/相机状态检查;预览 path、tool、origin、grid、limit、live plot 分层截图。
- 固定视口:
1440×900@1x、1280×800@1x、390×844@1x;另测 DPR 2,但不能以 DPR 2 代替 canonical。
9. 当前实现状态和下一步执行顺序
当前 React 已具备 AXIS 风格 shell、原始 bitmap toolbar、Manual/MDI 与 Preview/DRO 结构、Worker-backed program/MDI/jog/home/override/spindle/coolant/ESTOP/recover 入口和 Three.js 视角交互;这只证明实现切片,不等于本规范的 M1…M7 已验收。
M0 的 AXIS-INV-01…04 已执行:coverage/axis-source-inventory.report.json 由 scripts/generate_axis_source_inventory.py 生成,专属契约测试为 scripts/test_axis_source_inventory.py,当前冻结 10 个源码入口、31 个 bitmap 资源和 115 个精确 AXIS INI 案例,报告自哈希为 0ec92a467ca13700bd12a7f2889ada8aa11588ca50858dbe25f84a5c946b8176。该报告只冻结来源,不代表任何 Web 功能已通过行为或视觉验收。
接续执行顺序固定为:
AXIS-INV-01…04已完成;报告保留 exact path、source hash、asset hash 和 DISPLAY 声明。AXIS-CON-01…04已完成:coverage/axis-contract.report.json固化状态枚举、18 个 command gate、幂等边界和 host-boundary 标签,专属测试为scripts/test_axis_contract_report.py。AXIS-UI-01…07已完成 Chromium 结构证据:coverage/gui-browser-visual-fe-m4.report.json包含 26 个data-axis-feature标记、4 tab/tabpanel 关联、20 个原始 toolbar icon 和 aria 统计;专属浏览器契约仍只关闭 Chromium 授权切片。AXIS-CTRL-01…08已完成:coverage/axis-control.report.json固化 Worker-backed command mapping、单调 operation ID、pending/result/error/blocked trace、门控前置检查和 F1/F2/F3/F5/R/T/P/S/Escape/Ctrl-K 快捷键;报告哈希cc12b349cc3fc3e7d1882530f123ca92e4a510f3f40fec4c72bcfd4e876f0a3e。AXIS-VIEW-01…04和AXIS-EDIT-01:完成预览层、DRO 模式和选中行程序工作流。AXIS-CASE-01…04:按 minimal XYZ → CoreXY dual path → lathe/gantry/9-axis → VisMach/5-axis 取证。AXIS-TEST-01…06:Chromium visual/interaction/performance/recovery,外加明确的 Firefox/Safari/OPFS blocker。AXIS-REL-01/02:只有所有 P0/P1 和报告自哈希通过,才更新 release gate。
第一批可执行命令:
python3 scripts/validate_baseline.py
python3 scripts/validate_task_pointer.py
sha256sum linuxcnc/share/axis/tcl/axis.tcl linuxcnc/lib/python/gremlin.py linuxcnc/lib/python/rs274/glcanon.py
find linuxcnc/share/axis/images -maxdepth 1 -type f -printf '%f\n' | sort
npm --prefix web/react run typecheck
npm --prefix web/react run build
for f in web/app/test_*.mjs; do node "$f" || exit 1; done
执行者每完成一个任务,必须在对应报告中记录:源文件行号、Web 文件、命令/状态字段、测试命令、native/WASM/Worker 哈希、视觉视口、失败分类和下一依赖。没有这些字段的“完成”只算 implementation_present,不算 verified。
10. STOP_RELEASE 条件
出现以下任一项,立即停止扩大范围并将当前里程碑标为 blocked:
- AXIS 源、图标或案例输入变化但未重新生成 hash;
- 首个 divergent command/tick 未定位;
- UI 使用本地乐观状态伪造 task/position/IO 已执行;
- jog release、急停、恢复或 checkpoint 可能重复副作用;
- 缺少 native oracle 却宣称结果一致;
- host-only、真实硬件、动态 loader、外部窗口被统计为 Web 已支持;
- 视觉测试只比较截图,没有 DOM/交互/状态证据;
- 浏览器或 OPFS 不支持被静默降级;
- 任何报告无法用固定输入重新生成或 self-hash 不一致。
本规范关闭的是“AXIS 对标工程”而不是“LinuxCNC 全功能发布”声明。所有未实现、缺资源、无官方 oracle、浏览器边界和真实硬件排除项都必须保留在最终 evidence index 中。