Files
linuxcncWebWASM/docs/linuxcnc-axis-web-control-panel-source-logic.md

42 KiB

LinuxCNC AXIS Web Control Panel Source Logic

Status: active implementation contract
Scope: the selected XYZAC TRT Web/WASM panel and its LinuxCNC-compatible Worker command path
Source baseline: LinuxCNC submodule 239dcf4284762ad7e9c65d390bc5524d855c2f8e

Relationship map: linuxcnc-axis-web-control-panel-source-logic.png

Reproducible graph source: linuxcnc-axis-web-control-panel-source-logic.dot

This document is the control-flow authority for the Web panel. A button is implemented only when its complete path is defined here:

browser gesture
  -> React handler
  -> AxisOperationController operation
  -> SimSession command gate
  -> LinuxCNC/WASM task, interpreter, TP or IO authority
  -> canonical snapshot
  -> React projection

The React state is never an authority. A rejected Worker command must remain rejected in the UI, with the source gate reason visible as the disabled-button title and in Diagnostics.

The panel does not add a startup/run alias. The source-defined machine sequence is explicit: release E-stop when needed, power on, home, then press the single toolbar Run control (or the source R shortcut).

On browser startup, the selected INI is the only program-selection authority. For xyzac-trt.ini, [DISPLAY] OPEN_FILE selects ./demos/xyzac_switchkins.ngc, matching axis.py startup around initialfile/open_file_guts. Browser UI persistence must not restore a different G-code source or path and must never schedule a hidden second PROGRAM_LOAD after the configured file appears.

AXIS has both Machine/View menu bindings and toolbar/notebook bindings. The Web surface keeps the toolbar as the single machine-command entry point and the notebook tabs as the single view entry point. This removes duplicate buttons; the command, gate and source symbol for each retained entry are unchanged.

Source References

The primary GUI source is linuxcnc/src/emc/usr_intf/axis/scripts/axis.py. The accepted command and post-completion/abort behavior are also checked against linuxcnc/src/emc/task/emctaskmain.cc; the Web panel must not stop at the Python button handler when the LinuxCNC task layer defines an additional transition.

AXIS source symbol Role
manual_ok, ensure_mode Polling, task-state and mode preconditions
estop_clicked, onoff_clicked E-stop and machine power edges
open_file_guts File replacement transaction and mode restoration
task_run, task_run_line, task_step, task_pause, task_resume, task_pauseresume, task_stop Program execution lifecycle
send_mdi, send_mdi_command MDI history, mode and command submission
home_all_joints, home_joint Homing and joint/kinematics restrictions
touch_off_system, touch_off_tool Coordinate/tool offset dialogs and G10/G43 sequence
spindle, spindle_forward_toggle, spindle_backward_toggle, spindle_increase, spindle_decrease, spindle_constant Spindle direction, speed and brake controls
mist_toggle, flood_toggle, brake_on, brake_off Auxiliary IO controls
toggle_override_limits, cycle_view Limit override and preview view selection

The widget wiring is in linuxcnc/share/axis/tcl/axis.tcl: machine menu and toolbar bindings are around lines 105-170 and 490-669; manual jog, home, touch-off, spindle and coolant bindings are around lines 893-1087.

Source Surface Inventory

This inventory separates source controls from the smaller Web surface. A source-only or host-bound entry is documented explicitly rather than silently replaced by a different action.

Source surface Source entries Web treatment
File menu Open, Recent Files, Edit, Reload, Save As, Properties, Edit Tool Data, Reload Tool Data, Ladder Editor, Quit Open and Reload have one visible toolbar entry each. Edit Tool Data and Quit remain visible but disabled with a host-boundary reason. Other desktop-only entries are not rendered.
Machine menu E-stop, Power, Run, Run from selected line, Step, Pause, Resume, Stop, Optional Stop, Block Delete, MDI history, Calibration/HAL tools, Homing, Unhoming, Zero coordinate system, Tool touch-off target E-stop/Power/Run/Step/Pause/Resume/Stop/Home/Touch Off are represented by documented commands; Run-from-line, MDI clipboard/file actions, calibration/HAL desktop tools and Unhoming are not exposed; Optional Stop, Block Delete, Override Limits and Tool Touch Off remain ABI-blocked.
View menu Six preset views, inches/mm, show program/rapids/live plot/tool/extents/offsets/limits/velocity/DTG, grid, DRO font, PyVCP, commanded/actual, machine/relative, joint/world, clear plot Preset view/zoom/rotate, units, commanded/actual, machine/relative and supported visual layers are Web projections; unsupported teleop, grid/DTG/font/PyVCP settings are not aliased to motion state.
Toolbar E-stop, Power, Open, Reload, Run, Step, Pause/Resume, Stop, Block Delete, Optional Stop, zoom, six views, rotate, Clear Plot Same source order and icon assets are retained for supported controls; unsupported controls are disabled with a source/ABI reason.
Manual notebook Axis/joint selector, continuous/increment jog, Home Axis, Touch Off, Tool Touch Off, Override Limits, spindle direction/stop/speed/brake and coolant XYZAC axis selector, jog, Home Axis, Touch Off, spindle and coolant are represented. Joint selection, Tool Touch Off and Override Limits are explicitly bounded by the selected configuration/ABI. Tool and probe state is read-only; Prepare/Change/Arm/Disarm are IO/HAL operations, not AXIS main-panel controls.
Web case strip no AXIS equivalent Load exact XYZAC TRT case is a Web workspace/bootstrap control, not an AXIS source button. It may only call the same documented LOAD_WORKSPACE + PROGRAM_LOAD transaction and must not introduce a second Run/Power/Home flow.
MDI notebook MDI entry, Go, history selection/double-click, Up/Down history, Ctrl-M/H/Shift-H clipboard operations Entry, Go and local history are represented; clipboard/file history operations are host/UI-only and are not sent as machine commands.
Browser UI persistence AXIS preferences do not override [DISPLAY] OPEN_FILE with executable source text OPFS may persist presentation preferences such as view, zoom, tabs, units and selected axis. It must not persist or automatically load G-code source/path.

The Web surface may remove duplicate menu entries, but it may not change the meaning of a retained command. This is why Machine/View menus are not rendered when the same source action already has a toolbar or notebook entry.

Source Keyboard Contract

The following bindings are copied from axis.py lines 3109-3171. Keys that would require an unavailable command are listed as blocked instead of being silently mapped to another operation.

Key Source handler Web treatment
F1, F2, lowercase r, T, P, S, Esc, Ctrl-R, O, F7-F12 E-stop, power, run, step, pause, resume, stop, reload, open, coolant and spindle handlers Worker-backed commands with the same gate and ordering rules.
uppercase R, F task_reverse, task_forward Source controls are recorded as blocked because the selected WASM program ABI has no reverse/forward command; they are never mapped to Run.
Home, Ctrl-Home, End, Ctrl-End home_joint, home_all_joints, touch_off_system, touch_off_tool Home and system Touch Off are implemented; Tool Touch Off reports the documented ABI blocker.
x, y, z, a, c, -, =, Shift jog keys Axis selection and jog_on/jog_off Axis selection and pointer jog are implemented; browser key-jog remains limited to the visible selected axes.
c, i, I Continuous/incremental jog mode Represented by the jog increment selector; no second local mode state is created.
v, d, !, @, #, $ Cycle view, rotate, units, display type, coordinate type, teleop mode View/rotate/units/display/coordinate actions are projected; teleop mode is explicitly unavailable.
Ctrl-K clear_live_plot Worker visual-only VISUAL_CLEAR.
Ctrl-S, Ctrl-M/H/Shift-H, F4 Save G-code, MDI clipboard/history, next tab Save/clipboard operations are host/UI-boundary; F4 notebook cycling is a Web navigation action and does not alter machine state.

State Gates

Every motion or interpreter operation is evaluated against the canonical task, IO and trajectory state before the handler runs.

State Meaning in the panel
ESTOP E-stop input asserted. Only the reset edge and diagnostic-safe actions are available.
ESTOP_RESET E-stop released but power is not on. POWER(active=true) is the next machine edge.
OFF Machine power is off. File inspection/loading is allowed by LinuxCNC, but motion and MDI are not.
ON IO is ready. Manual operations still require an idle interpreter and the correct task mode.
RUNNING/PAUSED AUTO execution owns the interpreter. Manual, MDI, home, spindle and tool operations are blocked.
STOPPED A stopped taskfile remains recoverable; the next source-defined transition is IO_RECOVER, power or restart as applicable.

manual_ok() is equivalent to: poll, task state ON, not running, and either an idle interpreter or an MDI queue below its limit. ensure_mode() is a command transaction, not a React state assignment.

Control Matrix

Panel control React command Source flow and required result
Emergency Stop / Cancel ESTOP {active} estop_clicked toggles STATE_ESTOP and STATE_ESTOP_RESET; active E-stop aborts the interpreter and TP, then keeps the loaded taskfile.
Power on / off POWER {active} onoff_clicked toggles STATE_ON and STATE_OFF; power-off aborts motion but preserves the loaded file.
Open G-code file browser file + PROGRAM_LOAD open_file_guts: poll, save mode, enter MANUAL, restore the saved tab mode before PLAN_OPEN/program_open, set first line, synchronize, parse/preview, then set_mode_from_tab after refresh.
Load case / packaged program / edited source LOAD_WORKSPACE and/or PROGRAM_LOAD The Web case bootstrap and packaged-program selector use the same replacement transaction as open_file_guts. Edited text is submitted only through the single toolbar Reload command; the program pane has no duplicate Load/Run/Step buttons. Old preview is cleared before parsing and never reused after a failed replacement.
Switchkins Identity / TCP: XYZAC / User K KINEMATICS_SELECT {type} Selected-case remap equivalent for M429/M428/M430 from xyzac-trt.ini; requires homed, idle, empty TP queue and canonical HAL switchkins state.
Run PROGRAM_RUN run_warn, ensure_mode(AUTO), AUTO_RUN from the selected start line, then periodic task/TP ticks. Normal AXIS Run uses line 0. In emctaskmain.cc, an ended or aborted task plan is closed; the next EMC_TASK_PLAN_RUN reopens the current taskfile and runs from line 0. Therefore Run after completed or aborted must work directly and must not require a separate Reload/Restart click.
Run from selected line not exposed AXIS task_run_line requires an editor highlight and source AUTO_RUN start line. The Web editor has no source-line selection command yet, so no partial/fake button is rendered.
Reverse / Forward not exposed AXIS task_reverse/task_forward are keyboard-only source actions; the selected WASM program ABI has no corresponding command and Web preserves the distinction from Run.
Step PROGRAM_STEP ensure_mode(AUTO) when needed, issue AUTO_STEP, and keep the interpreter at the source line boundary.
Pause / Resume PROGRAM_PAUSE / PROGRAM_RESUME Pause only while AUTO is reading/waiting; resume only from the paused state. Polling ticks stop around the edge so a servo sample cannot race it.
Stop PROGRAM_ABORT AXIS enables Stop only while the interpreter is non-idle; then it highlights the active line, issues c.abort(), waits for completion, and clears the abort edge. The Worker may accept an internal abort edge in more states, but the Web button follows the AXIS UI gate.
Block delete / optional pause disabled LinuxCNC source has these controls, but the selected WASM ABI does not expose their canonical state. They are visible as disabled, with blocked_by_abi, and never emulate a local toggle.
Preview view, zoom, rotate, clear plot local view or VISUAL_CLEAR Visual-only operations do not change task, interpreter, TP or IO state. Ctrl-K maps AXIS clear_live_plot() and clears only the accumulated execution Live Plot; it must not delete the loaded program's static preview.
DRO coordinate/display/units local projection Maps AXIS coord_type, display_type and metric variables; values remain Worker snapshot projections.
Preview layers local projection Maps source show_live_plot, show_machine_limits, show_machine_speed, show_offsets and show_extents where the selected visual adapter has data; toggling a layer never changes motion.
Manual / MDI tabs SET_MODE The tab gesture sends an explicit Worker mode command. No background effect may change MANUAL after AUTO has started.
Joint/World (teleop) mode not exposed AXIS View menu calls set_teleop_mode/c.teleop_enable; the selected WASM motion ABI has no canonical teleop setter, so Web does not pretend its coordinate mode is a joint/world toggle.
Jog - / + JOG_START, repeated SIM_STEP, JOG_STOP jog_on/jog_off semantics. Incremental mode submits one TP segment; Continuous mode samples the source TP jog velocity until pointer release.
Home Axis HOME {axis} manual_ok, ensure_mode(MANUAL), then source joint-home command. Individual axis home is rejected outside identity kinematics, matching home_joint.
Home All / Re-home All HOME {all:true} manual_ok, ensure_mode(MANUAL), then home all joints. Once the canonical homed mask is complete, the Web label changes to RE-HOME ALL so loading another program is not mistaken for a requirement to home again. Activating Re-home retains the source home_all_joints confirmation. PROGRAM_LOAD never clears the homed mask and never invokes HOME.
Touch Off TOUCH_OFF {axis,value,system,units} Prompt for value and one of AXIS's all_systems entries (P0 Current, P1 G54 ... P9 G59.3), enter MDI, issue G10 L20 <P-token>, wait/synchronize, reload the active interpreter state and restore the saved mode.
Tool Touch Off TOOL_TOUCH_OFF {axis,value,system,units} LinuxCNC source requires G10 L10/L11 plus G43, but the selected WASM interpreter does not expose canonical tool-offset storage. The control is therefore disabled with blocked_by_abi_tool_offsets; it never sends a fake fixed G43.
Override limits disabled Source requires an active limit and an idle interpreter; the selected WASM limit override ABI is unavailable, so no unsafe local emulation is provided.
Spindle CCW / stop / CW SPINDLE_COMMAND manual_ok, ensure_mode(MANUAL), then source direction/stop command. The displayed pressed state is derived from canonical signed RPM.
Spindle - / + SPINDLE_COMMAND {delta} → SPINDLE_CONSTANT on release AXIS binds Button-1 to spindle_decrease/spindle_increase and ButtonRelease to spindle_constant; Web preserves this press/release sequence.
Brake SPINDLE_BRAKE Source brake command, gated by manual_ok.
Mist / Flood COOLANT_COMMAND Independent source coolant toggles; canonical device IO is returned after every edge.
Tool / probe status read-only AXIS does not put Prepare/Change/Arm/Disarm buttons in this manual notebook. Tool changes remain interpreter/MDI and IO/HAL operations. Web displays canonical tool/probe state but exposes no extra main-panel command buttons.
Jog Speed SET_JOG_SCALE update_jog_slider_vel writes the source linear jog scale.
Angular Jog Speed not exposed AXIS has a separate ajogspeed control for rotary joints; the selected WASM TP exposes one shared jog scale only, so the Web panel does not alias linear Jog Speed to this control.
Feed Override SET_OVERRIDE set_feedrate writes the source feed override; updates are debounced but ordered in the Worker queue.
Spindle Override SET_SPINDLE_OVERRIDE set_spindlerate writes canonical spindle override.
Max Velocity SET_MAX_VELOCITY AXIS set_maxvel calls c.maxvel and changes the trajectory velocity limit. The selected WASM TP exposes this as its velocity scale.
Rapid Override disabled AXIS set_rapidrate calls c.rapidrate and is distinct from Max Velocity. The selected WASM TP has no rapid-scale setter, so the Web control is disabled with blocked_by_abi_rapidrate.
MDI command/history MDI_EXECUTE send_mdi validates manual_ok, enters MDI, de-duplicates adjacent history entries and submits c.mdi.
File tool-data editor / Quit disabled AXIS launches a host editor or terminates the desktop process. Browser controls remain visibly disabled with host_boundary_tool_editor / host_boundary_process_quit; clicking them cannot report a false success.
About AXIS local dialog Mirrors the source .about dialog and its OK/close action. It changes no Worker, task, TP or IO state.

Complete Web Control Inventory

Every rendered actionable element has a stable data-axis-control value. This table is exhaustive for the selected XYZAC panel. A control may not be added to React until its ID, source mapping, gate and result are added here. Repeated MDI history rows intentionally share the family ID mdi-history-select.

Control ID(s) Source mapping Operation and gate Accepted result / disabled behavior
menu-file, menu-help axis.tcl File/Help cascades Local menu disclosure; always available Opens/closes menu only; no machine state change
menu-file-edit-tool-data, menu-file-quit edit_tooltable, quit host process operations Permanently disabled in a browser host_boundary_tool_editor / host_boundary_process_quit; no fake status success
menu-help-about, about-close .menu.help About entry and .about.ok Local modal open/close About visibility changes only
toolbar-estop .toolbar.machine_estop -> estop_clicked ESTOP {active}; accepted from every task state Toggle source E-stop edge; active edge aborts interpreter/TP
toolbar-power .toolbar.machine_power -> onoff_clicked POWER {active}; reset E-stop before power-on Canonical STATE_ON/STATE_OFF; power-off aborts motion
toolbar-open, program-file-input .toolbar.file_open -> open_file/open_file_guts File picker then PROGRAM_LOAD; interpreter must be IDLE One replacement transaction; input itself is hidden and only the toolbar button opens it
toolbar-load-case Web workspace boundary; uses INI DISPLAY, HAL, KINS and OPEN_FILE inputs LOAD_WORKSPACE then the documented PROGRAM_LOAD; IDLE only Reloads the selected exact case; never adds Power/Home/Run aliases
toolbar-reload .toolbar.reload -> reload_file PROGRAM_LOAD of current editor source/path; IDLE taskfile required Replaces preview/interpreter at line 0; this is the only visible commit action for edited source
toolbar-run .toolbar.program_run -> task_run PROGRAM_RUN; ON, taskfile, IDLE and task-layer homing gate AUTO/RUNNING from line 0; completed/aborted taskfile reopens directly
toolbar-step .toolbar.program_step -> task_step PROGRAM_STEP; ON, taskfile and homing gate AUTO_STEP then PAUSED at the next source boundary
toolbar-pause-resume .toolbar.program_pause -> task_pauseresume Pause while READING/WAITING; Resume while PAUSED One source toggle whose icon/label and command follow canonical pause state
toolbar-stop .toolbar.program_stop -> task_stop PROGRAM_ABORT; visible button enabled only for non-IDLE interpreter Abort, drain/clear TP and retain selected taskfile
toolbar-block-delete, toolbar-optional-pause Source toolbar toggles Permanently disabled for selected ABI blocked_by_abi; no React-only toggle
toolbar-zoom-in, toolbar-zoom-out zoomin, zoomout Local preview camera only Bounded camera zoom; task/TP unchanged
toolbar-view-z, toolbar-view-z2, toolbar-view-x, toolbar-view-y, toolbar-view-y2, toolbar-view-p set_view_z/z2/x/y/y2/p Local source view selection Exactly one pressed view; opens Preview tab; machine state unchanged
toolbar-rotate .toolbar.rotate Local drag/rotate projection Toggles pressed state and viewer interaction only
toolbar-clear-live-plot clear_live_plot -> positionlogger.clear() Worker VISUAL_CLEAR; always visual-only Advances live_path_epoch, clears Live Plot only and retains static preview
workspace-case-select Web selection of the INI/configuration input Local selection; selected catalog is restricted to supported XYZAC case Does not load or change machine state until toolbar-load-case
workspace-load-3d-chips Web packaged-file equivalent of open_file_guts Fetch published 3D_Chips.ngc, then PROGRAM_LOAD; IDLE only Same canonical file replacement path as Open; no automatic Run/Home
manual-home-all Machine Homing menu -> home_all_joints HOME {all:true}; manual_ok, then MANUAL First Home homes all; canonical homed mask changes label to Re-home; repeat asks source confirmation
switchkins-0, switchkins-1, switchkins-2 M429, M428, M430 remaps and motion.switchkins-type KINEMATICS_SELECT; ON, homed, IDLE, empty TP Identity/XYZAC/User K canonical type, or stable gate reason
tab-manual, tab-mdi AXIS notebook F3/F5 ensure_manual/ensure_mdi SET_MODE; no active AUTO motion Tab selection plus acknowledged MANUAL/MDI mode change
tab-diagnostics Web diagnostics boundary Local tab only Reads Worker state/gates; sends no command
tab-preview, tab-dro AXIS preview/DRO presentation Local tab only Changes visible projection; machine state unchanged
manual-axis-x, manual-axis-y, manual-axis-z, manual-axis-a, manual-axis-c AXIS axis radio group / ja_rbutton Local axis selection Supplies the selected axis to Jog/Home/Touch Off; sends no motion by itself
manual-jog-increment jogincrement combobox Local choice: Continuous or configured increment Determines JOG_CONTINUOUS versus JOG_INCREMENT payload only
manual-jog-negative, manual-jog-positive jogminus, jogplus -> jog_on JOG_START; visible Manual tab, ON, IDLE, homed Incremental submits once; Continuous repeats source-rate segments while held
manual-home-axis home_joint HOME {axis}; manual_ok, MANUAL, identity kinematics for coordinate-axis home Canonical joint home; repeated home asks confirmation
manual-touch-off touch_off_system TOUCH_OFF; ON, homed, IDLE, MANUAL and valid value/system MDI G10 L20, synchronize, reload and restore saved mode
manual-tool-touch-off touch_off_tool Permanently disabled for selected ABI blocked_by_abi_tool_offsets; never approximated with G92/fixed G43
manual-override-limits toggle_override_limits Permanently disabled for selected ABI No state mutation; explanatory ABI title
manual-spindle-ccw, manual-spindle-stop, manual-spindle-cw spindle radio group -> spindle SPINDLE_COMMAND; manual_ok, MANUAL Canonical signed RPM/direction determines pressed state
manual-spindle-decrease, manual-spindle-increase spindle_decrease/increase; ButtonRelease -> spindle_constant Enabled only while spindle direction is nonzero, matching axis.tcl update_state Press sends speed edge without crossing through zero into the opposite direction; release/cancel sends SPINDLE_CONSTANT
manual-spindle-brake brake SPINDLE_BRAKE; same manual source gate Canonical brake state controls checkbox
manual-coolant-mist, manual-coolant-flood manual-group mist/flood controls COOLANT_COMMAND; visible checkboxes require ON and IDLE Independent canonical coolant bits; disabled during AUTO activity
mdi-command, mdi-submit MDI entry and send_mdi Local text; submit/Enter sends MDI_EXECUTE under manual_ok/queue gate Trimmed nonempty block, MDI mode, canonical interpreter result
mdi-history-select AXIS MDI history row selection Local history selection Copies selected prior command into entry; does not execute until Submit/Enter
preview-panLeft, preview-panRight, preview-panUp, preview-panDown, preview-reset Web accessible equivalent of Gremlin mouse pan/reset Local camera only Moves/resets camera; no Worker command
dro-coordinate, dro-display, dro-units coord_type, display_type, metric Local snapshot projection Machine/Relative, Actual/Commanded and mm/inch display only
override-jog-speed update_jog_slider_vel SET_JOG_SCALE; source jog gate Canonical linear jog scale
override-feed set_feedrate Debounced SET_OVERRIDE; ON Canonical feed override, including while AUTO where task layer permits
override-spindle set_spindlerate SET_SPINDLE_OVERRIDE; ON Canonical spindle override
override-max-velocity set_maxvel SET_MAX_VELOCITY; ON Canonical TP velocity limit/scale
override-rapid set_rapidrate Permanently disabled for selected ABI blocked_by_abi_rapidrate; never aliases Max Velocity
preview-layer-path, preview-layer-live, preview-layer-limits, preview-layer-velocity, preview-layer-offsets, preview-layer-extents AXIS View visibility variables Local visibility only Shows/hides existing snapshot data without deleting or mutating it
program-editor Browser replacement for AXIS external Edit boundary Edits pending source text locally Does not change loaded interpreter until toolbar-reload

Tool/probe IO operations (TOOL_PREPARE, TOOL_PREPARED, TOOL_CHANGE, TOOL_CHANGED, PROBE_CONFIG) remain Worker capabilities for interpreter, MDI, HAL and focused IO tests. They are deliberately absent from the Web main panel because no corresponding AXIS main-panel buttons exist.

Button Dependency Matrix

The following matrix describes the side effects that determine the next set of enabled controls. The right-hand column is an observable Worker state change; React must derive its button gates from that state on the next snapshot.

Action Must be true before the click State change after acceptance Controls affected next
ESTOP(active=true) Always accepted by the task state machine IO estop=1, ready=0; interpreter and TP aborted; task ESTOP; loaded source retained Disable power-on, home, jog, MDI, spindle, tool, probe and all program controls except E-stop reset/recovery-safe actions
ESTOP(active=false) E-stop input is asserted IO estop clears; task becomes STOPPED/ESTOP_RESET; power remains off Enable Power On; keep all motion/interpreter operations disabled
POWER(active=true) E-stop clear, interpreter idle, task not running IO ready=1; task READY/machine ON Enable Home and source-gated manual/program controls; Run still requires homed and a taskfile
POWER(active=false) Machine on (source accepts the immediate off edge) Abort motion/interpreter, IO ready=0, loaded taskfile retained Disable motion, MDI, home and Run; allow Power On after the off edge
HOME(all/axis) Machine on, interpreter idle, homing gate true Home-limit authority sets homed mask; individual non-identity home is rejected Enables Run/MDI/jog only after the canonical homed result is published
PROGRAM_LOAD Interpreter idle, TP/MDI motion queue empty, source file/path valid Enters MANUAL for replacement setup, captures the current canonical TP pose, restores the saved mode before PLAN_OPEN-equivalent parsing, replaces the interpreter source, applies the task_plan_synch pose before preview/subroutine processing, then reapplies the selected tab mode Run/Step/Restart gates are recalculated from the new taskfile; old preview/trace is unavailable during parse and incremental coordinates start from the synchronized machine pose
KINEMATICS_SELECT Machine on, homed, idle, TP queue empty, valid type 0/1/2 M429/M428/M430 selection updates canonical kinematics and the HAL switchkins type Identity is required for individual coordinate-axis homing; a non-empty queue blocks selection
SET_MODE(MANUAL) Machine on, no active AUTO/MDI motion Task mode becomes MANUAL Enables manual jog/home/spindle/tool gates when idle; disables AUTO-only pause/resume
SET_MODE(MDI) Machine on, interpreter idle or MDI queue below limit Task mode becomes MDI Enables MDI submission; manual controls follow manual_ok and queue policy
PROGRAM_RUN AXIS toolbar projection: machine ON and interpreter IDLE. Task acceptance additionally requires a current taskfile and, unless NO_FORCE_HOMING is configured, all required joints homed. completed and aborted are valid idle starting states. If the previous task plan ended or was aborted, reopen/rewind the current taskfile at line 0; set mode AUTO, program RUNNING, and begin TP samples. A short program may pass through RUNNING and reach completed before the next UI paint; that is successful execution, not a blocked Run. Disable Load, MDI, Home, Jog, spindle and tool operations while active; enable Pause and Stop. On completion, Run becomes available again for another line-0 execution.
PROGRAM_PAUSE AUTO program is reading/waiting Program/task PAUSED; run polling is stopped around the edge Disable Pause and Stop-as-new-run; enable Resume; keep E-stop and Power Off available
PROGRAM_RESUME Program/task is paused Program/task RUNNING; TP polling resumes Re-enable Pause and Stop; keep manual/MDI/home disabled
PROGRAM_ABORT AXIS exposes Stop while machine ON and interpreter non-IDLE; the task abort command itself is immediate Interpreter aborts, TP queue is cleared, current taskfile/path remains selected, and the open task plan is closed Stop periodic run polling; direct Run is enabled again when the task is idle and reopens the same taskfile from line 0. Reload is not a prerequisite.
JOG_START Machine on, idle/manual gate, homed One incremental segment or repeated continuous TP segments are queued While held, another jog direction is not started; release/cancel must issue JOG_STOP
JOG_STOP An active jog gesture exists Active jog is aborted/stopped; TP remains runnable Allows a subsequent jog, MDI or source-gated manual command
TOUCH_OFF Machine on, homed, idle/manual gate and valid dialog value MDI G10 L20 updates the selected coordinate system, then the saved mode is restored Position/DRO and offsets refresh; program run state is unchanged
SET_MAX_VELOCITY Machine powered and the override gate permits the update Source TP velocity limit is changed Motion duration/velocity changes; jog and feed overrides remain independent
Rapid Override control Not available in the selected WASM TP No state change Rapid Override remains disabled; Max Velocity must not be used as a substitute
Spindle/Coolant Visible manual controls require machine ON and interpreter IDLE; spindle also requires MANUAL mode Canonical device IO changes only after Worker verification Pressed/checked states update from device IO; spindle speed +/- additionally requires a running spindle, matching axis.tcl update_state

Dependency Flow

ESTOP ──release──> ESTOP_RESET ──POWER ON──> ON
                                         │
                                         ├──HOME ALL──> homed ON
                                         │                 │
                                         │                 ├──RUN──> AUTO/RUNNING
                                         │                 │             ├──PAUSE──> PAUSED
                                         │                 │             │              └──RESUME──> RUNNING
                                         │                 │             └──STOP/ESTOP/POWER OFF──> idle loaded taskfile
                                         │                 └──MANUAL/MDI──> jog/home/offset/device gates
                                         └──PROGRAM LOAD──> loaded taskfile (idle only)

Any E-stop or power-off edge invalidates the downstream branch immediately. The UI must not leave a stale enabled button visible while it waits for the next canonical snapshot; the Worker gate remains the final authority even if a click races a state transition.

Required Transactions

Startup program selection

read selected INI
 -> resolve [DISPLAY] OPEN_FILE
 -> keep preview/program controls in loading state
 -> LOAD_WORKSPACE
 -> exactly one PROGRAM_LOAD for the configured OPEN_FILE
 -> publish the configured program, source hash and preview atomically
 -> enable source-gated controls

The UI cache is read only for presentation preferences. A stale cached program from an earlier Web version is ignored and replaced on the next UI preference save. No default-preview-then-cached-preview transition is permitted.

File replacement

poll
 -> reject if AUTO is running/paused
 -> save task mode
 -> ensure MANUAL
 -> clear previous preview and pending TP/interpreter edges
 -> restore saved task mode before PLAN_OPEN-equivalent parsing
 -> capture current canonical TP pose
 -> set first line / PROGRAM_LOAD
 -> task_plan_synch equivalent: initialize the new interpreter from that TP pose
 -> subroutine load + preview from the same synchronized pose
 -> reapply selected tab mode after the UI refresh
 -> publish one canonical replacement snapshot

The replacement is rejected while the TP or an MDI move still has a queued or active segment. Loading program B after program A has moved the machine must never reset the interpreter to the origin. For example, if A ends at X10, a new B program beginning with G91 G1 X5 previews and executes from X10 to X15, not from X0 to X5.

E-stop recovery and startup

ESTOP(active=true)
 -> abort interpreter and TP
 -> task ESTOP, IO estop=1, ready=0
ESTOP(active=false)
 -> IO estop=0, task STOPPED (ESTOP_RESET)
POWER(active=true)
 -> IO ready=1, task READY/ON
HOME(all=true)
 -> MANUAL mode, all joints homed
PROGRAM_RUN
 -> if the previous plan is completed/aborted: reopen current taskfile at line 0
 -> AUTO mode, RUNNING, periodic SIM_STEP until completion

Run after completion or Stop

RUNNING -> M2/end-of-file -> WAITING -> queue/IO drained -> IDLE/completed
                                                       -> press Run
                                                       -> reopen current taskfile
                                                       -> AUTO_RUN line 0

RUNNING -> Stop/abort -> abort interpreter + TP -> close task plan -> IDLE/aborted
                                                               -> press Run
                                                               -> reopen current taskfile
                                                               -> AUTO_RUN line 0

This is the source behavior in emctaskmain.cc: closing the task plan avoids resuming at an aborted line, and EMC_TASK_PLAN_RUN_TYPE opens the selected file again when no plan is open. The Web runtime may expose PROGRAM_RESTART internally for recovery/testing, but it is not a required user step and is not a second visible Run control. After the reopen/synchronization, a positioning block whose target already equals the current canonical pose is a zero-motion block: it advances the interpreter line but must not enqueue an invalid zero-length TP segment.

Touch-off command encoding

AXIS's all_systems list is P0 Current, P1 G54 through P9 G59.3. touch_off_system passes the first token from the selected entry to G10 L20, so the source command is G10 L20 P1 X... for G54 (and P0 for the current system). The Worker accepts the same P-token or a G54..G59.3 display token, records the normalized source_system, and executes the same canonical P form. This keeps the source command and the interpreter encoding auditable without changing the UI behavior.

Continuous jog

AXIS binds Button-1 to continuous jog and ButtonRelease to jog_stop. The Web equivalent keeps a single active {axis,direction} gesture, issues one source-TP jog segment per 50 ms sample using the canonical jog velocity, advances one servo sample, and sends JOG_STOP exactly once on release, cancel, leave or E-stop.

Toolpath display lifecycle

The panel renders two different path layers. They must never share an implicit clear condition:

Layer Source owner Visible/retained Cleared or replaced
Static program preview open_file_guts creates AxisCanon; Gremlin renders the parsed canon Remains visible during Run, Pause, Resume, Stop and normal completion A new PROGRAM_LOAD hides the old preview while parsing, then replaces it atomically with the newly parsed program. A failed replacement must not relabel the old path as the new program.
Machining Live Plot LivePlotter/linuxcnc.positionlogger; show_live_plot controls visibility Accumulates during motion. Pause freezes and retains it. Resume continues the same trace. Stop and normal completion retain the accumulated trace. Hiding the Live layer changes visibility only and does not delete data. AXIS clear_live_plot() explicitly calls logger.clear(). The Web panel additionally starts a documented new machining epoch for an accepted PROGRAM_RUN, PROGRAM_RESTART, or PROGRAM_LOAD, as required for this panel: the previous machining trace is cleared without changing the static preview or any task/TP state.

The Worker publishes a monotonic visual.live_path_epoch. React may clear the machining Live Plot only when this value changes. Array identity, a full versus delta snapshot, Pause, Resume, Stop, task mode, queue depth and completion are not clear signals.

PROGRAM_LOAD accepted -> increment live_path_epoch -> clear old live trace
                      -> hide old static preview while parsing
                      -> publish new static preview

PROGRAM_RUN accepted  -> increment live_path_epoch -> begin a new live trace
PROGRAM_PAUSE          -> epoch unchanged -> retain/freeze live trace
PROGRAM_RESUME         -> epoch unchanged -> continue live trace
PROGRAM_ABORT/STOP     -> epoch unchanged -> retain live trace
program completed      -> epoch unchanged -> retain live trace
VISUAL_CLEAR           -> increment live_path_epoch -> clear live trace only
PROGRAM_RESTART        -> increment live_path_epoch -> clear live trace

If Clear Plot is used while motion is still active, history before the clear edge is removed and positionlogger semantics immediately begin accumulating the subsequent motion in the new epoch. At IDLE, the cleared trace stays empty.

The additional Web epoch at a new Run/load boundary is a presentation lifecycle rule requested for this panel. It does not pretend that AXIS calls positionlogger.clear() from task_run or open_file_guts: the native source does not. Pause/completion retention and explicit Clear Plot behavior remain direct source matches.

Implementation Invariants

  1. web/worker/sim-session.mjs is the command gate and transaction boundary.
  2. web/worker/wasm-linuxcnc-tp.mjs, wasm-program-runtime.mjs, wasm-xyzac-io.mjs and wasm-xyzac-device-io.mjs are the only authorities for selected-case motion, interpreter and device state.
  3. web/react/src/App.tsx may render a button disabled from a gate snapshot, but a Worker gate is still mandatory because UI state can be stale.
  4. Every accepted operation produces a ledger entry and canonical snapshot; every rejected operation produces a stable source/gate reason.
  5. A feature that cannot be represented by the selected ABI is disabled with an explicit reason. It must not be approximated with G92, a fixed G43, local booleans or a second JavaScript state machine.
  6. New controls must be added to this matrix, the source symbol inventory and a focused Worker/browser regression test before deployment.
  7. Executable program source/path is never part of UI preference persistence; refresh performs one INI-authorized startup load.
  8. Live Plot clearing is controlled only by the Worker live_path_epoch; React object/array replacement is never a lifecycle signal.

Change Procedure

Focused evidence for this contract is kept in web/worker/test_xyzac_touch_off_source_flow.mjs, web/worker/test_xyzac_panel_buttons.mjs and scripts/test_xyzac_panel_buttons_browser.mjs. The completed/aborted direct rerun contract is covered by web/worker/test_xyzac_program_rerun.mjs and the published-site execution sequence is covered by scripts/test_xyzac_program_execution_browser_strict.mjs. The source-surface audit is enforced by scripts/test_axis_control_contract.mjs. The exhaustive control-ID audit is enforced by scripts/test_axis_control_inventory.mjs and scripts/test_axis_control_inventory_browser.mjs; the latter rejects any rendered actionable element without a documented ID or with a duplicate ID.

When LinuxCNC source behavior or the selected machine configuration changes:

  1. Update the source baseline and the affected matrix row/transaction above.
  2. Update the Worker gate/authority path.
  3. Update the React handler only after the Worker contract is verified.
  4. Add normal, blocked and recovery assertions to the focused test.
  5. Run the panel browser test, build the React bundle, and publish a new release directory without replacing the previous rollback target.

The document deliberately records ABI blockers and source boundaries. A verified Web slice means the implemented path matches this contract; it does not claim that an unavailable LinuxCNC host or official native oracle has been silently reproduced in the browser.