Background / Coolant
+Environment: Ambient Temperature / Coolant
-Background and Coolant are two leaves of the General Setup page's Control Tree
-(/general-setup?tree=equipment/background, /general-setup?tree=equipment/coolant), sitting
-directly under the General Setup group between Spindle Capability and Fixture. They are two tree
-items rather than a page, so the older /equipment/background-coolant path redirects onto the
-Background leaf. Both are served by one panel component, which branches on the selected node's role
-path.
Ambient Temperature and Coolant are the two leaves of the General Setup page's Environment root
+(/general-setup?tree=equipment/background/environment-temperature,
+/general-setup?tree=equipment/background/coolant — the root's id equipment/background and the
+routes keep the legacy background spelling; since 2026-09-15 Environment is one of the page's four
+roots beside Mechanism, Spindle Capability and Controller, and the pre-regroup equipment/coolant id
+migrates). They are tree items rather than a page, so the older /equipment/background-coolant path
+redirects onto the Environment root. Both leaves are served by one panel component, which branches
+on the selected node's role path.
They edit the thermal condition on the project's authored equipment face, SetupEquipment, reached as SetupEquipment:
-
-
- BackgroundTemperature_C (Background +
- AmbientTemperature_C (Ambient leaf)
- the whole CoolantHeatCondition (Coolant leaf) — file-first, see below
Layout
-
-
- Background leaf —
equipment/background, item typeThermalCondition+ - Ambient Temperature leaf —
equipment/background/environment-temperature, item typeThermalCondition-
-
- Background Temperature NumberField (°C) — -BackgroundTemperature_C. +
- Ambient Temperature NumberField (°C) — +AmbientTemperature_C.
- Coolant leaf —
equipment/coolant, the same item type and the same panel (file pick on top, @@ -177,11 +179,11 @@ are the water-soluble preset's values.
but exposes - Finite values only. Every field handler drops a null or non-finite entry before any request is
made, so
Infinitynever reaches these endpoints even though the numeric widget can parse it. -Background and coolant temperatures accept negatives (e.g. -40 °C for cryogenic coolant); the +Ambient and coolant temperatures accept negatives (e.g. -40 °C for cryogenic coolant); the three convection fields are clamped tomin: 0.
- - The run sees it at once. The background-temperature write, all four condition scalars and the +
- The run sees it at once. The ambient-temperature write, all four condition scalars and the file load each end in the project service's ForwardSetupEnvironmentToExecution, which stamps the -background temperature and the condition reference onto the runtime equipment face — including +ambient temperature and the condition reference onto the runtime equipment face — including the lazily created condition, which otherwise would exist only on the authored side.
_C accessors that handle the conversion, and the DTO carries Celsius.
Source Code Path
@@ -190,7 +192,7 @@ the lazily created condition, which otherwise would exist only on the authored sHiNC-2025-webservice (Quasar CLI SPA):
wwwroot-src/src/components/controlTree/ThermalConditionPanel.vue— the one panel both leaves -share, branching on the node's last role-path segment: Background renders the single temperature +share, branching on the node's last role-path segment: Ambient Temperature renders the single temperature field, Coolant the not-attached badge, the file row, the read-only Name / Note and the four property fields.wwwroot-src/src/components/controlTree/useControlTreeHost.ts— declares the two @@ -207,7 +209,8 @@ the flat snapshot, the load / save-as pair, and the five scalar PUTs.wwwroot-src/src/router/routes.ts— carries theequipment/background-coolantredirect, which lands ongeneral-setup?tree=equipment/background.Mech/BackgroundCoolantController.cs— REST surface at/api/mech/background-coolantover the -authored equipment face: +authored equipment face (the route, the PUT path and the snapshot field keep their legacy +backgroundwire names; only the C# member behind them is renamed):GET /— flat snapshot{ hasEquipment, backgroundTemperature_C, hasCoolant, coolantTemperature_C, coolantConvectionCoefficient_Wdm2K, mistFloodConvectionRatio, offConvectionCoefficient_Wdm2K, coolantName, coolantNote, coolantHeatConditionFile }.POST /load,POST /save-as—{ rootName, relFile }: install a.CoolantHeatConditionfile @@ -218,7 +221,7 @@ project-relative path when it lands under the project. Save-as appends the exten missing and renames the condition after the file (IPreferredFileName) with the.defaultmarker stripped.PUT /background-temperature-c— set -BackgroundTemperature_C.
+AmbientTemperature_C.
PUT /coolant-temperature-c,PUT /coolant-convection-coefficient-wdm2k,PUT /mist-flood-convection-ratio,PUT /off-convection-coefficient-wdm2k— the four condition scalars, all through one helper that lazy-creates the condition when absent, writes it, and @@ -233,7 +236,7 @@ flood / mist-ratio / off convection coefficients, Name and Note withPrefeStandardPresets/ApplyPreset/MatchStandardPresetstatics behind the shipped resource files.HiMech/Machining/MachiningEquipmentUtils/SetupEquipment.cs— the authored equipment face that -owns the background temperature, the condition and its file reference, and externalizes the +owns the ambient temperature, the condition and its file reference, and externalizes the condition to the side-file when that reference is set.
See Also
diff --git a/App/wwwroot/HiAPI-docsite/anatomy/general-setup/controller/machine/per-axis-tables.html b/App/wwwroot/HiAPI-docsite/anatomy/general-setup/controller/machine/per-axis-tables.html index 89877c1b..05463eec 100644 --- a/App/wwwroot/HiAPI-docsite/anatomy/general-setup/controller/machine/per-axis-tables.html +++ b/App/wwwroot/HiAPI-docsite/anatomy/general-setup/controller/machine/per-axis-tables.html @@ -372,7 +372,13 @@ bounded field on the four leaves, at zero or above.The stroke limits are checked at each played step against the chain's current machine pose while the
session's stroke-limit check is on; a position past a configured limit is reported as a
stroke-limit validation error anchored to that step, and pauses the player when pause-on-failure is
-set. The check walks a fixed axis vocabulary — X, Y and Z from the machine point, A, B and C
+set. The comparison carries a small tolerance
+(Tolerance), so an axis parked exactly on its limit
+is not reported. The rotary limits also steer the tilt solves: when a G53.1, G68.2, CYCLE800,
+PLANE SPATIAL or LN posture has its nearest rotary solution outside the travel, the solve takes
+the admissible branch nearest the entry instead of commanding a posture the machine cannot take. A
+project that declared its travel only in the legacy machine-limits boxes gets those ends copied into
+this table on load, for the axes carrying no end here. The check walks a fixed axis vocabulary — X, Y and Z from the machine point, A, B and C
from its orientation — so a limit stored against any other axis name is kept and shown here but never
tested. Rapid-traverse timing has the same shape and the same six names: a G00 move is timed
axis-by-axis at each axis' rate and takes the slowest, falling back to the same 20000 mm/min and
diff --git a/App/wwwroot/HiAPI-docsite/anatomy/general-setup/index.html b/App/wwwroot/HiAPI-docsite/anatomy/general-setup/index.html
index 2b76e344..0009dee1 100644
--- a/App/wwwroot/HiAPI-docsite/anatomy/general-setup/index.html
+++ b/App/wwwroot/HiAPI-docsite/anatomy/general-setup/index.html
@@ -104,7 +104,7 @@ application.
- Machine Tool — The kinematic chain the whole scene hangs from, and the standalone route that loads and previews it
- Spindle Capability — The spindle envelope: thermal condition, gear shift, dry run, power and torque -
- Background / Coolant — The two scene branches that are not machine parts: the backdrop and the coolant model +
- Environment: Ambient Temperature / Coolant — The Environment root's two thermal leaves, the ones that are not machine parts: the ambient (shop) temperature the thermal model starts from, and the coolant model
- Fixture — What holds the workpiece, its geometry and the two anchors that place it
- Workpiece — Raw and target geometry, the anchors that locate them, the mesh, and the material
- Controller — The SoftNcRunner-native controller branch: its two planes, the brand matrix behind which nodes appear at all, and the contract every leaf edits by diff --git a/App/wwwroot/HiAPI-docsite/anatomy/general-setup/spindle-capability.html b/App/wwwroot/HiAPI-docsite/anatomy/general-setup/spindle-capability.html index 361fc02e..c7ee8788 100644 --- a/App/wwwroot/HiAPI-docsite/anatomy/general-setup/spindle-capability.html +++ b/App/wwwroot/HiAPI-docsite/anatomy/general-setup/spindle-capability.html @@ -290,7 +290,7 @@ reference.
- Mechanism Builder Page — same file-level IO pattern (Load / Reload / Save As) but user-scoped rather than project-scoped. -
- Background / Coolant — sibling branch of the same Control Tree, editing the same authored equipment face. +
- Environment: Ambient Temperature / Coolant — sibling root of the same Control Tree, editing the same authored equipment face.
- Spindle Capability — what the model represents physically and how the per-step ratios come out of it.
- - Background / Coolant + Environment (Ambient Temperature / Coolant)
-
Fixture
diff --git a/App/wwwroot/HiAPI-docsite/anatomy/general-setup/toc.json b/App/wwwroot/HiAPI-docsite/anatomy/general-setup/toc.json
index 636d2b17..a242f168 100644
--- a/App/wwwroot/HiAPI-docsite/anatomy/general-setup/toc.json
+++ b/App/wwwroot/HiAPI-docsite/anatomy/general-setup/toc.json
@@ -1,2 +1,2 @@
-{"items":[{"name":"Overview","href":"index.html","topicHref":"index.html"},{"name":"Machine Tool","href":"machine-tool.html","topicHref":"machine-tool.html"},{"name":"Spindle Capability","href":"spindle-capability.html","topicHref":"spindle-capability.html"},{"name":"Background / Coolant","href":"background-coolant.html","topicHref":"background-coolant.html"},{"name":"Fixture","href":"fixture.html","topicHref":"fixture.html"},{"name":"Workpiece","href":"workpiece.html","topicHref":"workpiece.html"},{"name":"Controller","href":"controller/index.html","tocHref":"controller/toc.html","topicHref":"controller/index.html","homepage":"controller/index.html"},{"name":"Hidden Controller Branches","href":"hidden-controllers.html","topicHref":"hidden-controllers.html"}]}
+{"items":[{"name":"Overview","href":"index.html","topicHref":"index.html"},{"name":"Machine Tool","href":"machine-tool.html","topicHref":"machine-tool.html"},{"name":"Spindle Capability","href":"spindle-capability.html","topicHref":"spindle-capability.html"},{"name":"Environment (Ambient Temperature / Coolant)","href":"background-coolant.html","topicHref":"background-coolant.html"},{"name":"Fixture","href":"fixture.html","topicHref":"fixture.html"},{"name":"Workpiece","href":"workpiece.html","topicHref":"workpiece.html"},{"name":"Controller","href":"controller/index.html","tocHref":"controller/toc.html","topicHref":"controller/index.html","homepage":"controller/index.html"},{"name":"Hidden Controller Branches","href":"hidden-controllers.html","topicHref":"hidden-controllers.html"}]}
diff --git a/App/wwwroot/HiAPI-docsite/anatomy/legacy-controller-settings.html b/App/wwwroot/HiAPI-docsite/anatomy/legacy-controller-settings.html
index 94f4bdcb..1c329bb8 100644
--- a/App/wwwroot/HiAPI-docsite/anatomy/legacy-controller-settings.html
+++ b/App/wwwroot/HiAPI-docsite/anatomy/legacy-controller-settings.html
@@ -121,12 +121,16 @@ session holds no played SoftNc layers, and it is handed
MachiningProject.N the switch on, so a value that only the legacy endpoints or the project XML can change still shows up on a runner play.-
-
- Stroke limits, as a fallback. The per-step stroke check reads the runner's +
- Stroke limits, as a fallback and as a seed. The per-step stroke check reads the runner's IStrokeLimitConfig when the switch is on and one is present, and falls back to the legacy stroke boxes otherwise — a CSV or NX-CL suit carries no stroke config, so -a play on those falls through to the boxes. The pre-play audit that warns of an unlimited linear -axis reads both sources end by end, the runner's first and the legacy box behind it, and stays -silent for an axis either source guards. +a play on those falls through to the boxes. When a project loads, the boxes' finite ends are also +copied into the runner's controller parameter table for every axis that carries no end there +(PopulateLegacyStrokeLimitsWhereUnset; an explicit row wins), so +a project that declared its travel only in the boxes is checked against it on SoftNc — and its +tilt solves prefer the rotary branch inside that travel. The pre-play audit that warns of an +unlimited linear axis reads both sources end by end, the runner's first and the legacy box behind +it, and stays silent for an axis either source guards.
- The home position, as a fallback. The chain is re-homed from the runner's home config; the
legacy
HomeMcfills in only when no linear axis was ever configured there. - The Execution canvas's coordinate markers. The
IsoCoordinateandHeidenhainCoordinatediff --git a/App/wwwroot/HiAPI-docsite/anatomy/platform/control-tree.html b/App/wwwroot/HiAPI-docsite/anatomy/platform/control-tree.html index b9940c29..49b04b03 100644 --- a/App/wwwroot/HiAPI-docsite/anatomy/platform/control-tree.html +++ b/App/wwwroot/HiAPI-docsite/anatomy/platform/control-tree.html @@ -116,7 +116,7 @@ segment is a scope key only.
re-minted on every re-index; in the Mission branch it is the Mission API command path ( ctx— the parent-providedSlotCtx: theafterChangecommit chain, a slot'sonCreatecreate-and-rebind hook, and a slot picker'sallowedKinds/allowNoneconstraints.
diff --git a/App/wwwroot/HiAPI-docsite/anatomy/platform/tree-ids-and-routes.html b/App/wwwroot/HiAPI-docsite/anatomy/platform/tree-ids-and-routes.html
index 33e38ee7..2a2822fe 100644
--- a/App/wwwroot/HiAPI-docsite/anatomy/platform/tree-ids-and-routes.html
+++ b/App/wwwroot/HiAPI-docsite/anatomy/platform/tree-ids-and-routes.html
@@ -209,7 +209,7 @@ moved into a Control Tree still lands on the editor.
- Tool House MenuItem Open Tool House Page
- General Setup MenuItem -The equipment Control Tree — Machine Tool, Spindle Capability, Background, Coolant, Fixture, Workpiece, Controller, in that order — plus the shared equipment canvas. Two further controller branches, CSV Controller and CL Controller, are hidden by default and are switched on from the Preference dropdown. +The equipment Control Tree — four roots: Mechanism (Machine Tool / Fixture / Workpiece), Spindle Capability, Environment (Ambient Temperature / Coolant) and Controller, in that order — plus the shared equipment canvas. Two further controller branches, CSV Controller and CL Controller, are hidden by default and are switched on from the Preference dropdown.
- Execution MenuItem Open Execution Page
- File Explorer MenuItem (below a separator). See Util Pages.
- Mechanism Builder MenuItem Open Mechanism Builder Page -
- @@ -203,7 +203,7 @@ watching for project changes itself.
- The Execution Page is the landing route —
/redirects to/execution - The page URL and panel state are synchronized (bi-directional navigation) -
- There is no Environment dropdown. Machine Tool, Fixture, Workpiece, Controller, Background / Coolant and Spindle Capability are branches of the General Setup page's Control Tree, and Tool House and Execution are pages of their own; the remaining paths resolve as redirects into those pages. The menu bar is therefore
Project ▾ | Page ▾ | Preference ▾.
+ - There is no Environment dropdown (Environment is now a root of the General Setup page's Control Tree, over Ambient Temperature / Coolant). Mechanism (Machine Tool / Fixture / Workpiece), Spindle Capability, Environment and Controller are the roots of that tree, and Tool House and Execution are pages of their own; the remaining paths resolve as redirects into those pages. The menu bar is therefore
Project ▾ | Page ▾ | Preference ▾. - double + +
- double + +
- double + +
- double + +
WorkpieceServiceWorkpieceServiceService that owns the workpiece being machined.
- BackgroundTemperature_Kdouble
- Background temperature in Kelvin.
+AmbientTemperature_Kdouble
+ Ambient temperature in Kelvin.
CoolantHeatConditionCoolantHeatConditionThe coolant heat condition.
@@ -258,6 +258,38 @@ it may span two steps back. + + ++ AmbientTemperature_K + +
+ ++ + +Ambient temperature in Kelvin.
+++ + + + + +
+public double AmbientTemperature_K { get; init; }Property Value
+-
+
- double + +
@@ -290,38 +322,6 @@ it may span two steps back. - - -
- BackgroundTemperature_K - -
- -- - -Background temperature in Kelvin.
--- - - - - -
-public double BackgroundTemperature_K { get; init; }Property Value
--
-
- double - -
diff --git a/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.LocalProjectService.html b/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.LocalProjectService.html index ba776596..865126ab 100644 --- a/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.LocalProjectService.html +++ b/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.LocalProjectService.html @@ -2222,7 +2222,7 @@ no-op, for hosts without a setup face (e.g. test stubs).
-Forwards the authored environment values (background temperature, +
Forwards the authored environment values (ambient temperature, coolant condition, spindle capability) onto the runtime face. These are pure data with no topology involvement, so eager forwarding is safe and keeps environment edits immediate — a full materialise is not needed @@ -3735,6 +3735,46 @@ The previous step is null if no previous step exists.
++ OnNcPipelineReset + +
+ ++ + +App-lifetime event raised after the per-session NC pipeline state has been +rewound (Hi.MachiningProcs.LocalProjectService.ResetNcPipelineState()): the next +RunNcLines(string, IEnumerable<string>, MachiningSession, StepDiagnosticProgress, NcDiagnosticProgress, CancellationToken) re-initialises from scratch, so its +FileIndex / SentenceIndex counters restart at 0. Raised on EVERY rewind path — +a runner-suit rewire (brand switch), PowerReset() and +ResetRuntime(IProgress<IMessage>) (including a mission script's
+ResetRuntime()+between two NC files) — not only on a PacePlayer reset or a project swap, +which are the two boundaries a session-lifetime consumer already sees. Anything +keyed by those counters must drop its index here, or the next file's pieces +land under the previous file's numbers.++ + + + + + +
+public event Action OnNcPipelineResetEvent Type
+-
+
- Action + +
OnShellMessageAdded diff --git a/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.MachiningParallelProc.StepTaskBundle.html b/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.MachiningParallelProc.StepTaskBundle.html index 72d26470..d0128609 100644 --- a/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.MachiningParallelProc.StepTaskBundle.html +++ b/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.MachiningParallelProc.StepTaskBundle.html @@ -190,13 +190,13 @@ Class MachiningParallelProc.StepTaskBundle
-
+public StepTaskBundle(double backgroundTemperature_K, double spindleTemperature_K)public StepTaskBundle(double ambientTemperature_K, double spindleTemperature_K)Parameters
-
-
backgroundTemperature_Kdouble
- The background temperature in Kelvin.
+ambientTemperature_Kdouble
+ The ambient temperature in Kelvin.
spindleTemperature_KdoubleThe spindle temperature in Kelvin.
diff --git a/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.RapidCutMonitor.html b/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.RapidCutMonitor.html index 5725406e..544878ae 100644 --- a/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.RapidCutMonitor.html +++ b/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.RapidCutMonitor.html @@ -6,7 +6,7 @@ - + @@ -105,7 +105,7 @@ the line's first touching step and carrying the line's total removed volume and its largest cutting depth. A rapid move through material breaks the tool or crashes the machine on a real run, yet with the spindle turning the engine treats it as ordinary cutting: the collision -rule (Hi.Machining.MachiningEquipment.Detect) pairs flute +rule (Detect(bool)) pairs flute and workpiece only while the spindle is stopped, so such a line used to pass with no message at all.diff --git a/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.html b/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.html index 1e7f7ebe..fd2cdb80 100644 --- a/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.html +++ b/App/wwwroot/HiAPI-docsite/api/Hi.MachiningProcs.html @@ -222,7 +222,7 @@ the line's first touching step and carrying the line's total removed volume and its largest cutting depth. A rapid move through material breaks the tool or crashes the machine on a real run, yet with the spindle turning the engine treats it as ordinary cutting: the collision -rule (Hi.Machining.MachiningEquipment.Detect) pairs flute +rule (Detect(bool)) pairs flute and workpiece only while the spindle is stopped, so such a line used to pass with no message at all.
diff --git a/App/wwwroot/HiAPI-docsite/api/Hi.Physics.SeqPhysicsBrief.html b/App/wwwroot/HiAPI-docsite/api/Hi.Physics.SeqPhysicsBrief.html index 7e9a5453..85d5b599 100644 --- a/App/wwwroot/HiAPI-docsite/api/Hi.Physics.SeqPhysicsBrief.html +++ b/App/wwwroot/HiAPI-docsite/api/Hi.Physics.SeqPhysicsBrief.html @@ -229,13 +229,13 @@ Class SeqPhysicsBrief
-
+public SeqPhysicsBrief(double backgroundTemperature_K, double spindleTemperature_K)public SeqPhysicsBrief(double ambientTemperature_K, double spindleTemperature_K)Parameters
-
-
backgroundTemperature_Kdouble
- The background temperature in Kelvin.
+ambientTemperature_Kdouble
+ The ambient temperature in Kelvin.
spindleTemperature_KdoubleThe spindle temperature in Kelvin.
@@ -1050,7 +1050,7 @@ public double WorkpieceSurfaceTemperature_C { get; set; }-
+public void BuildCuttingTemperatureAndWear(SeqPhysicsBrief preSeqPhysicsBrief, MachineMotionStep preMachineMotionStep, MachineMotionStep curMachineMotionStep, double backgroundTemperature_K, SpindleCapability spindleCapability, IMachiningTool machiningTool, Workpiece workpiece, int stepIndex, Substraction substraction, LayerMillingEngagement layerMillingEngagement, MillingPhysicsBrief millingPhysicsBrief, CoolantHeatCondition coolantHeatCondition, CoolantMode coolantMode, bool enableWearEffect, MillingToolPhysicsPack physicsPack = null, Action<string> onWarning = null)public void BuildCuttingTemperatureAndWear(SeqPhysicsBrief preSeqPhysicsBrief, MachineMotionStep preMachineMotionStep, MachineMotionStep curMachineMotionStep, double ambientTemperature_K, SpindleCapability spindleCapability, IMachiningTool machiningTool, Workpiece workpiece, int stepIndex, Substraction substraction, LayerMillingEngagement layerMillingEngagement, MillingPhysicsBrief millingPhysicsBrief, CoolantHeatCondition coolantHeatCondition, CoolantMode coolantMode, bool enableWearEffect, MillingToolPhysicsPack physicsPack = null, Action<string> onWarning = null)Parameters
@@ -1064,8 +1064,8 @@ public double WorkpieceSurfaceTemperature_C { get; set; }curMachineMotionStepMachineMotionStepThe current machine motion step.
- backgroundTemperature_Kdouble
- The background temperature in Kelvin.
+ambientTemperature_Kdouble
+ The ambient temperature in Kelvin.
spindleCapabilitySpindleCapabilityThe spindle capability information.
@@ -1135,7 +1135,7 @@ derivations on use.-
+public void BuildSpindleTemperatureAndRatio(MachineMotionStep machiningStep, MillingPhysicsBrief rakeFacePhysicsBrief, double backgroundTemperature_K, SpindleCapability spindleCapability, SpindleSpeedCache spindleSpeedCache, double preSpindleTemperature_K)public void BuildSpindleTemperatureAndRatio(MachineMotionStep machiningStep, MillingPhysicsBrief rakeFacePhysicsBrief, double ambientTemperature_K, SpindleCapability spindleCapability, SpindleSpeedCache spindleSpeedCache, double preSpindleTemperature_K)Parameters
@@ -1144,7 +1144,7 @@ derivations on use.rakeFacePhysicsBriefMillingPhysicsBrief
- backgroundTemperature_Kdouble
+ ambientTemperature_KdoublespindleCapabilitySpindleCapability
diff --git a/App/wwwroot/HiAPI-docsite/index.json b/App/wwwroot/HiAPI-docsite/index.json
index b55d6b4d..dbf72d21 100644
--- a/App/wwwroot/HiAPI-docsite/index.json
+++ b/App/wwwroot/HiAPI-docsite/index.json
@@ -7,7 +7,7 @@
"anatomy/by-source/webservice-backend.html": {
"href": "anatomy/by-source/webservice-backend.html",
"title": "Web Service Backend Source Tree | HiAPI-C# 2025",
- "summary": "Web Service Backend Source Tree The C# half of HiNC-2025-webservice is an ASP.NET Core process that serves the SPA, answers its REST calls, and pushes to it over SignalR. It is organised by the engine's domain vocabulary, not by web-framework artifact type: a controller, its hub, its DI service and its non-web scene objects sit together in one domain folder rather than in a Controllers / Hubs / Services split. Folders below are ordered by how much of the shipped surface they answer for. Reading a Filename The role of a file is told by its suffix and base type, and the convention holds throughout: Suffix What it is *Controller.cs a REST controller with a route attribute *Hub.cs a SignalR hub — but see the two traps below *Service.cs a singleton registered in Program.cs *Displayee.cs a scene-composition object handed to the engine; no HTTP surface at all *Dtos.cs, *Config.cs plain wire or settings types Two names deliberately break the reader's expectation. Controller/ControllerController.cs means CNC controller, not an MVC controller. And Mech/'s *DisplayController.cs files are ordinary REST controllers that attach a displayee to a rendering connection somebody else already owns — they are not hubs. Important Folder nesting does not predict the route. Mech/Topo/ and Mech/MechBuilder/ expose routes that carry no api/mech/ prefix at all, and even inside Mech/ two conventions coexist: the newer ports use kebab-case paths under api/mech/, while the older keyed-object editors use the controller-name default. Read the route attribute, never the path. Composition Root Program.cs is the only C# file at the repository root, and it is where the questions a reader usually has are actually answered: which services are singletons, which hubs are mapped, and what the middleware order is. Two facts about it are worth carrying: A declared hub is not a mapped hub. Program.cs maps eight hub endpoints. Anything not in that list is unreachable however complete its class looks — see the trap under Execution/ below. The tree is not self-contained. The project service types Program.cs leans on hardest live in the sibling HiNc engine repository, not here. Documented in Program and Hosting. Execution Execution/ is the run cockpit's whole backend: playback control, the strip and cycle-line charts, the NC-program branch index, run-output queries, and the real-time push layer. Execution/ExecutionController.cs — the playback surface. Execution/ExecutionChartsController.cs and Execution/ClStripController.cs — the chart data. Three separate classes share the case-insensitive api/execution prefix on purpose, one of them routed there rather than under Mission with a comment saying why. Execution/SessionSinkHub.cs — four mapped hubs declared in one file, one per message sink, so hub-per-file does not hold here. Each pairs with a broadcast service that Program.cs resolves eagerly, so it subscribes to its sink before the first client connects. Execution/ClStripHub.cs, Execution/ExecutionStatusHub.cs — the strip and status pushes. Warning Execution/ExecutionCanvasHub.cs declares a hub that Program.cs never maps and that nothing in the repository references. The Execution canvas rides Disp/RenderingHub.cs like every other canvas. A reader looking for “the hub behind the Execution page” by name will find this file first and be wrong. Documented in Execution Page, Program Branch, Selected-Step Info Panel, Strip Charts and Cycle-Line Charts. Mech Mech/ is the largest domain folder: the REST surfaces for the machine tool, the tool house and cutter editing, fixtures and workpieces, spindle capability, background and coolant, and the three runner suits. It also holds the display controllers that bind a mechanism scene onto a rendering connection. Mech/CutterDtoBuilder.cs is the shared read-side DTO shape two controllers reuse, and Mech/NcSuitUsage.cs is what lets the Control Tree show the CSV and CL runner branches only when the loaded project actually plays them. No SignalR hub lives here. Mech/MechBuilder/ — the standalone mechanism-building session, held by a process-wide singleton rather than per user. Documented in Mechanism Builder Page. Mech/Topo/ — one thin controller per transformer kind, each editing an instance held in the keyed object store. Documented in Transformer Select Panel. Mech/SoftNcRunnerController.cs — the one endpoint family behind the Controller branch, and the file whose snapshot decides which of that branch's nodes exist. Documented in Controller Branch, with Brand Matrix for the snapshot flags themselves. Mech/CsvRunnerController.cs and Mech/ClRunnerController.cs — the two resident non-brand runner suits, reached from tree branches the Preference menu hides by default. Documented in Preference Menu Dropdown until those branches have a page. Documented in General Setup Page and Tool House Page and the panels beneath them. Missions Missions/ is the mission command tree's backend. Two things here surprise readers: The folder is plural and the route is singular — and the SPA folder is singular too. Missions/NcOptOptionEndpoints.cs is not a minimal-API endpoint file despite the name. It is a second file of the same partial controller class, which is why its routes resolve under the mission prefix. Missions/MissionCommandCatalog.cs reflects over every session command carrying the catalog attribute once per process, replacing hand-maintained kind switches, and Missions/MissionCommandFields.cs does the same for annotated scalars — which is how a simple command gets an editor without a bespoke panel. Missions/ScriptCompletionService.cs and Missions/ScriptCompileCheckService.cs are the Roslyn pair behind the script editor; the compile check reuses the same options and globals type the script command uses at run time. Documented in Mission Root Panel and the command panels under it. Disp Disp/ is the rendering layer. Disp/RenderingHub.cs is the single transport surface for every 3D canvas in the application — canvas initialization, pointer, key and touch input, resize, view presets, cache clearing and snapshots — and the SPA's canvas component defaults to it, so all pages share one hub rather than one hub per page. Disp/RenderingService.cs owns the per-connection engines the hub resolves against. Disp/StlPreviewController.cs is the only other REST surface here. The *Displayee.cs files are scene-graph composition objects rather than web types, and each has a live instantiation site: the execution scene, the equipment-setup scene, the step-subtraction scene and the two coordinate-frame displayees the first two compose in. Documented in Rendering Canvas on Web Service, RenderingCanvas Tool Bar and — for Disp/StlPreviewController.cs and the per-connection slot behind it — STL Preview Pane. Environments Environments/ is session and environment scope: the project lifecycle, per-user preference persistence, the Execution page's division flags, and the shipped localized step-present catalog. It is also where the Log Viewer's data comes from — the log endpoints sit on the project controller beside status, new, load, save, reload, save-as and close. Documented in Main Panel, Session State, Preference Menu Dropdown, Internationalization, Log Viewer Page and Step Present Dialog. Common, Geom and Widget Common/ — cross-cutting infrastructure with no single domain owner: the optional login gate, the named-root file explorer, path guards, the daily file logger, and two pieces the whole application rests on. Common/IndexService.cs is the keyed object store behind the index a backend object, then edit it by key pattern every geometry, transformer and widget controller uses. Common/CleanupHub.cs is not a messaging hub, and it is not what bounds that store either. Its key registry is an ordinary instance property and SignalR builds a fresh hub instance for every invocation, so the entry Add records is discarded with the instance that received it and the disconnect handler always walks an empty registry. The bound comes from the browser instead: wwwroot-src/src/composables/useCleanupHub.ts posts the index-remove endpoint on Common/IndexController.cs for every key it holds when its host unmounts, and again whenever a key it registered is replaced. Documented in Dictionary Service Pattern, WebAPI Hub Cleanup Pattern, Login and Authentication and Log Viewer Page. Geom/ — one CRUD controller per geometry kind, on the same keyed-object pattern, and nothing else: no hubs, no services. Documented in Geometry Panels. Widget/ — the generic value and lifecycle controllers the reusable inputs post to: the 3D vector, the 4×4 matrix, and the object-management surface that handles file operations, XML editing and copy-paste for indexed objects. Documented in Object Management Menu Button, Vec3dControl Component and Mat4dControl Component. Controller and Demo Controller/ is the single-file surface over the legacy HardNcEnv model, MachiningProject.NcEnv. The Legacy Controller page that drove it was removed on 2026-09-11, but the controller is still mounted: its routes edit the legacy tables, a different store from the runner tables that Mech/SoftNcRunnerController.cs — its successor, as that file's own doc comment says — edits. The successor covers the brand, the axis limits and rapid feedrates, the tooling time, the work coordinates, the datum tables and the tool offsets, but not every route — among them the work-coordinate Align P0 pair, the shortest-rotary toggle, the per-axis max rotary speed and the Heidenhain master-axis character have no soft-runner endpoint. Only GET cnc-brand still has a client — the Execution tool bar's Heidenhain Coordinate gate. Documented in Legacy Controller Model (HardNcEnv). Demo/ is customer-facing sample code — a custom colour guide and a per-step optimization sweep — compiled into the assembly with no call site in the running application. Read it as an example of how to extend the engine, not as part of the shipped behaviour. See Also Anatomy by Source Directory — the other two source trees, and how this layer is meant to be entered Web Service SPA Source Tree — the front end this process serves and answers"
+ "summary": "Web Service Backend Source Tree The C# half of HiNC-2025-webservice is an ASP.NET Core process that serves the SPA, answers its REST calls, and pushes to it over SignalR. It is organised by the engine's domain vocabulary, not by web-framework artifact type: a controller, its hub, its DI service and its non-web scene objects sit together in one domain folder rather than in a Controllers / Hubs / Services split. Folders below are ordered by how much of the shipped surface they answer for. Reading a Filename The role of a file is told by its suffix and base type, and the convention holds throughout: Suffix What it is *Controller.cs a REST controller with a route attribute *Hub.cs a SignalR hub — but see the two traps below *Service.cs a singleton registered in Program.cs *Displayee.cs a scene-composition object handed to the engine; no HTTP surface at all *Dtos.cs, *Config.cs plain wire or settings types Two names deliberately break the reader's expectation. Controller/ControllerController.cs means CNC controller, not an MVC controller. And Mech/'s *DisplayController.cs files are ordinary REST controllers that attach a displayee to a rendering connection somebody else already owns — they are not hubs. Important Folder nesting does not predict the route. Mech/Topo/ and Mech/MechBuilder/ expose routes that carry no api/mech/ prefix at all, and even inside Mech/ two conventions coexist: the newer ports use kebab-case paths under api/mech/, while the older keyed-object editors use the controller-name default. Read the route attribute, never the path. Composition Root Program.cs is the only C# file at the repository root, and it is where the questions a reader usually has are actually answered: which services are singletons, which hubs are mapped, and what the middleware order is. Two facts about it are worth carrying: A declared hub is not a mapped hub. Program.cs maps eight hub endpoints. Anything not in that list is unreachable however complete its class looks — see the trap under Execution/ below. The tree is not self-contained. The project service types Program.cs leans on hardest live in the sibling HiNc engine repository, not here. Documented in Program and Hosting. Execution Execution/ is the run cockpit's whole backend: playback control, the strip and cycle-line charts, the NC-program branch index, run-output queries, and the real-time push layer. Execution/ExecutionController.cs — the playback surface. Execution/ExecutionChartsController.cs and Execution/ClStripController.cs — the chart data. Three separate classes share the case-insensitive api/execution prefix on purpose, one of them routed there rather than under Mission with a comment saying why. Execution/SessionSinkHub.cs — four mapped hubs declared in one file, one per message sink, so hub-per-file does not hold here. Each pairs with a broadcast service that Program.cs resolves eagerly, so it subscribes to its sink before the first client connects. Execution/ClStripHub.cs, Execution/ExecutionStatusHub.cs — the strip and status pushes. Warning Execution/ExecutionCanvasHub.cs declares a hub that Program.cs never maps and that nothing in the repository references. The Execution canvas rides Disp/RenderingHub.cs like every other canvas. A reader looking for “the hub behind the Execution page” by name will find this file first and be wrong. Documented in Execution Page, Program Branch, Selected-Step Info Panel, Strip Charts and Cycle-Line Charts. Mech Mech/ is the largest domain folder: the REST surfaces for the machine tool, the tool house and cutter editing, fixtures and workpieces, spindle capability, ambient and coolant, and the three runner suits. It also holds the display controllers that bind a mechanism scene onto a rendering connection. Mech/CutterDtoBuilder.cs is the shared read-side DTO shape two controllers reuse, and Mech/NcSuitUsage.cs is what lets the Control Tree show the CSV and CL runner branches only when the loaded project actually plays them. No SignalR hub lives here. Mech/MechBuilder/ — the standalone mechanism-building session, held by a process-wide singleton rather than per user. Documented in Mechanism Builder Page. Mech/Topo/ — one thin controller per transformer kind, each editing an instance held in the keyed object store. Documented in Transformer Select Panel. Mech/SoftNcRunnerController.cs — the one endpoint family behind the Controller branch, and the file whose snapshot decides which of that branch's nodes exist. Documented in Controller Branch, with Brand Matrix for the snapshot flags themselves. Mech/CsvRunnerController.cs and Mech/ClRunnerController.cs — the two resident non-brand runner suits, reached from tree branches the Preference menu hides by default. Documented in Preference Menu Dropdown until those branches have a page. Documented in General Setup Page and Tool House Page and the panels beneath them. Missions Missions/ is the mission command tree's backend. Two things here surprise readers: The folder is plural and the route is singular — and the SPA folder is singular too. Missions/NcOptOptionEndpoints.cs is not a minimal-API endpoint file despite the name. It is a second file of the same partial controller class, which is why its routes resolve under the mission prefix. Missions/MissionCommandCatalog.cs reflects over every session command carrying the catalog attribute once per process, replacing hand-maintained kind switches, and Missions/MissionCommandFields.cs does the same for annotated scalars — which is how a simple command gets an editor without a bespoke panel. Missions/ScriptCompletionService.cs and Missions/ScriptCompileCheckService.cs are the Roslyn pair behind the script editor; the compile check reuses the same options and globals type the script command uses at run time. Documented in Mission Root Panel and the command panels under it. Disp Disp/ is the rendering layer. Disp/RenderingHub.cs is the single transport surface for every 3D canvas in the application — canvas initialization, pointer, key and touch input, resize, view presets, cache clearing and snapshots — and the SPA's canvas component defaults to it, so all pages share one hub rather than one hub per page. Disp/RenderingService.cs owns the per-connection engines the hub resolves against. Disp/StlPreviewController.cs is the only other REST surface here. The *Displayee.cs files are scene-graph composition objects rather than web types, and each has a live instantiation site: the execution scene, the equipment-setup scene, the step-subtraction scene and the two coordinate-frame displayees the first two compose in. Documented in Rendering Canvas on Web Service, RenderingCanvas Tool Bar and — for Disp/StlPreviewController.cs and the per-connection slot behind it — STL Preview Pane. Environments Environments/ is session and environment scope: the project lifecycle, per-user preference persistence, the Execution page's division flags, and the shipped localized step-present catalog. It is also where the Log Viewer's data comes from — the log endpoints sit on the project controller beside status, new, load, save, reload, save-as and close. Documented in Main Panel, Session State, Preference Menu Dropdown, Internationalization, Log Viewer Page and Step Present Dialog. Common, Geom and Widget Common/ — cross-cutting infrastructure with no single domain owner: the optional login gate, the named-root file explorer, path guards, the daily file logger, and two pieces the whole application rests on. Common/IndexService.cs is the keyed object store behind the index a backend object, then edit it by key pattern every geometry, transformer and widget controller uses. Common/CleanupHub.cs is not a messaging hub, and it is not what bounds that store either. Its key registry is an ordinary instance property and SignalR builds a fresh hub instance for every invocation, so the entry Add records is discarded with the instance that received it and the disconnect handler always walks an empty registry. The bound comes from the browser instead: wwwroot-src/src/composables/useCleanupHub.ts posts the index-remove endpoint on Common/IndexController.cs for every key it holds when its host unmounts, and again whenever a key it registered is replaced. Documented in Dictionary Service Pattern, WebAPI Hub Cleanup Pattern, Login and Authentication and Log Viewer Page. Geom/ — one CRUD controller per geometry kind, on the same keyed-object pattern, and nothing else: no hubs, no services. Documented in Geometry Panels. Widget/ — the generic value and lifecycle controllers the reusable inputs post to: the 3D vector, the 4×4 matrix, and the object-management surface that handles file operations, XML editing and copy-paste for indexed objects. Documented in Object Management Menu Button, Vec3dControl Component and Mat4dControl Component. Controller and Demo Controller/ is the single-file surface over the legacy HardNcEnv model, MachiningProject.NcEnv. The Legacy Controller page that drove it was removed on 2026-09-11, but the controller is still mounted: its routes edit the legacy tables, a different store from the runner tables that Mech/SoftNcRunnerController.cs — its successor, as that file's own doc comment says — edits. The successor covers the brand, the axis limits and rapid feedrates, the tooling time, the work coordinates, the datum tables and the tool offsets, but not every route — among them the work-coordinate Align P0 pair, the shortest-rotary toggle, the per-axis max rotary speed and the Heidenhain master-axis character have no soft-runner endpoint. Only GET cnc-brand still has a client — the Execution tool bar's Heidenhain Coordinate gate. Documented in Legacy Controller Model (HardNcEnv). Demo/ is customer-facing sample code — a custom colour guide and a per-step optimization sweep — compiled into the assembly with no call site in the running application. Read it as an example of how to extend the engine, not as part of the shipped behaviour. See Also Anatomy by Source Directory — the other two source trees, and how this layer is meant to be entered Web Service SPA Source Tree — the front end this process serves and answers"
},
"anatomy/by-source/webservice-spa.html": {
"href": "anatomy/by-source/webservice-spa.html",
@@ -141,8 +141,8 @@
},
"anatomy/general-setup/background-coolant.html": {
"href": "anatomy/general-setup/background-coolant.html",
- "title": "Background / Coolant | HiAPI-C# 2025",
- "summary": "Background / Coolant Background and Coolant are two leaves of the General Setup page's Control Tree (/general-setup?tree=equipment/background, /general-setup?tree=equipment/coolant), sitting directly under the General Setup group between Spindle Capability and Fixture. They are two tree items rather than a page, so the older /equipment/background-coolant path redirects onto the Background leaf. Both are served by one panel component, which branches on the selected node's role path. They edit the thermal condition on the project's authored equipment face, SetupEquipment, reached as SetupEquipment: BackgroundTemperature_C (Background leaf) the whole CoolantHeatCondition (Coolant leaf) — file-first, see below Key Model: SetupEquipment (+ its CoolantHeatCondition). Layout Background leaf — equipment/background, item type ThermalCondition Background Temperature NumberField (°C) — BackgroundTemperature_C. Coolant leaf — equipment/coolant, the same item type and the same panel (file pick on top, properties below, as on the workpiece material leaf) “Not attached” badge — visible until the first coolant-related save (see Lazy CoolantHeatCondition creation below). File row — FilePathInput (.CoolantHeatCondition, resource subfolder CoolantHeatCondition): a Select dropdown button whose menu holds Browse…, Browse Resource… and — only while a file is set — Clear, beside a read-only path input; it loads a saved condition by named root. A Save As… button follows it, prompting for a project-relative file to export the current condition to. Tracked in CoolantHeatConditionFile. The three standard cooling types ship as ready-made files in HiNc-Resource (Resource/CoolantHeatCondition/StandardForcedAir.default.CoolantHeatCondition, StandardOilBasedCoolant.default.CoolantHeatCondition and StandardWaterSolubleCoolant.default.CoolantHeatCondition), so Browse Resource… starts populated like the workpiece-material picker — picking a shipped file is the cooling-type selection. Name / Note — read-only mirror of the loaded condition. Property fields (always visible, under Name / Note): Coolant Temperature (°C) — CoolantTemperature_C. Flood Convection Coefficient (W/(m²·K)) — CoolantConvectionCoefficient_Wdm2K, min: 0. Mist / Flood Ratio — MistFloodConvectionRatio, min: 0. Off (Air) Convection Coefficient (W/(m²·K)) — OffConvectionCoefficient_Wdm2K, min: 0. Both leaves, with no project open: every control is disabled and a “no project — open one first” caption is shown. The panel fetches the snapshot itself on mount and gates on its hasEquipment flag, so the tree host holds no state for either leaf. Behavior File-based conditions (WorkpieceMaterial pattern). Picking a .CoolantHeatCondition file installs it as the whole condition (XFactory.GenByFile); Save As… exports the current values and renames the condition after the file (IPreferredFileName). While CoolantHeatConditionFile is set, the project save externalizes the condition as
and regenerates the side-file (a resource pick is copied into the project on save); with no file the bare inline shape is kept byte-compatible. Coefficient edits tune this project's copy. The static presets on CoolantHeatCondition (StandardPresets / ApplyPreset / MatchStandardPreset) are the API-side source the shipped files are authored from. The file row's Clear entry does nothing here. FilePathInput reports a clear by emitting update:modelValue(null), and this panel binds the widget's value one-way and listens only for picked — so the entry is rendered, is clickable while a file is set, and drops nothing. Clearing the tracked file is therefore not reachable from this leaf at all; the reference changes only by loading another file or by a Save As. The .default marker never survives a user save. The shipped resource files carry a .default ownership marker in their names. The Save As… prompt strips it from its prefill, and the controller strips it again from the name it stamps on the condition, so a user save cannot mint a file that masquerades as a shipped default. The “not attached” badge is unreachable, and the lazy creation behind it never fires. SetupEquipment initializes CoolantHeatCondition at its declaration and nothing assigns null to it — the project-XML read replaces the instance only when the element is present — so the controller's hasCoolant, which is a null test on that property, is true whenever a project is open. The badge is therefore rendered only in the no-equipment case the panel already covers with its own caption, and the null branch each scalar PUT carries is defensive rather than reached. What a fresh project actually carries is the class defaults, which are the water-soluble preset's values. Celsius is the wire format. CoolantHeatCondition stores Kelvin internally but exposes _C accessors that handle the conversion, and the DTO carries Celsius. Finite values only. Every field handler drops a null or non-finite entry before any request is made, so Infinity never reaches these endpoints even though the numeric widget can parse it. Background and coolant temperatures accept negatives (e.g. -40 °C for cryogenic coolant); the three convection fields are clamped to min: 0. The run sees it at once. The background-temperature write, all four condition scalars and the file load each end in the project service's ForwardSetupEnvironmentToExecution, which stamps the background temperature and the condition reference onto the runtime equipment face — including the lazily created condition, which otherwise would exist only on the authored side. Source Code Path See HiNC App Anatomy for git repository links. Web Application HiNC-2025-webservice (Quasar CLI SPA): wwwroot-src/src/components/controlTree/ThermalConditionPanel.vue — the one panel both leaves share, branching on the node's last role-path segment: Background renders the single temperature field, Coolant the not-attached badge, the file row, the read-only Name / Note and the four property fields. wwwroot-src/src/components/controlTree/useControlTreeHost.ts — declares the two ThermalCondition leaves (equipment/background, equipment/coolant) under the General Setup group, with no host-level init state. wwwroot-src/src/components/controlTree/itemTypes.ts — registers the ThermalCondition item type against that panel: no child tree, no geometry-cache chain. wwwroot-src/src/components/widgets/FilePathInput.vue — the file row widget: Browse… / Browse Resource… (opening at the CoolantHeatCondition resource subfolder) / Clear. wwwroot-src/src/components/widgets/NumericInput.vue — the numeric field used by every value on both leaves, and the source of the min: 0 clamp on the three convection fields. wwwroot-src/src/api/backgroundCoolant.ts — typed client for /api/mech/background-coolant/*: the flat snapshot, the load / save-as pair, and the five scalar PUTs. wwwroot-src/src/router/routes.ts — carries the equipment/background-coolant redirect, which lands on general-setup?tree=equipment/background. Mech/BackgroundCoolantController.cs — REST surface at /api/mech/background-coolant over the authored equipment face: GET / — flat snapshot { hasEquipment, backgroundTemperature_C, hasCoolant, coolantTemperature_C, coolantConvectionCoefficient_Wdm2K, mistFloodConvectionRatio, offConvectionCoefficient_Wdm2K, coolantName, coolantNote, coolantHeatConditionFile }. POST /load, POST /save-as — { rootName, relFile }: install a .CoolantHeatCondition file / export the current condition. Both resolve the path under the named root and refuse anything that escapes it, and both record the result in CoolantHeatConditionFile as a project-relative path when it lands under the project. Save-as appends the extension when it is missing and renames the condition after the file (IPreferredFileName) with the .default marker stripped. PUT /background-temperature-c — set BackgroundTemperature_C. PUT /coolant-temperature-c, PUT /coolant-convection-coefficient-wdm2k, PUT /mist-flood-convection-ratio, PUT /off-convection-coefficient-wdm2k — the four condition scalars, all through one helper that lazy-creates the condition when absent, writes it, and forwards to the runtime face. HiAPI Engine HiMech/Physics/CoolantHeatCondition.cs — the model: Kelvin storage with _C accessors, the flood / mist-ratio / off convection coefficients, Name and Note with PreferredFileName, and the StandardPresets / ApplyPreset / MatchStandardPreset statics behind the shipped resource files. HiMech/Machining/MachiningEquipmentUtils/SetupEquipment.cs — the authored equipment face that owns the background temperature, the condition and its file reference, and externalizes the condition to the side-file when that reference is set. See Also Spindle Capability — sibling equipment editor, editing the same authored equipment face. Coolant (manual) — the end-user task: picking a cooling type in the application. Coolant Model — what the values on this panel mean, which one a running program applies, and how the condition is stored." + "title": "Environment: Ambient Temperature / Coolant | HiAPI-C# 2025", + "summary": "Environment: Ambient Temperature / Coolant Ambient Temperature and Coolant are the two leaves of the General Setup page's Environment root (/general-setup?tree=equipment/background/environment-temperature, /general-setup?tree=equipment/background/coolant — the root's id equipment/background and the routes keep the legacy background spelling; since 2026-09-15 Environment is one of the page's four roots beside Mechanism, Spindle Capability and Controller, and the pre-regroup equipment/coolant id migrates). They are tree items rather than a page, so the older /equipment/background-coolant path redirects onto the Environment root. Both leaves are served by one panel component, which branches on the selected node's role path. They edit the thermal condition on the project's authored equipment face, SetupEquipment, reached as SetupEquipment: AmbientTemperature_C (Ambient leaf) the whole CoolantHeatCondition (Coolant leaf) — file-first, see below Key Model: SetupEquipment (+ its CoolantHeatCondition). Layout Ambient Temperature leaf — equipment/background/environment-temperature, item type ThermalCondition Ambient Temperature NumberField (°C) — AmbientTemperature_C. Coolant leaf — equipment/coolant, the same item type and the same panel (file pick on top, properties below, as on the workpiece material leaf) “Not attached” badge — visible until the first coolant-related save (see Lazy CoolantHeatCondition creation below). File row — FilePathInput (.CoolantHeatCondition, resource subfolder CoolantHeatCondition): a Select dropdown button whose menu holds Browse…, Browse Resource… and — only while a file is set — Clear, beside a read-only path input; it loads a saved condition by named root. A Save As… button follows it, prompting for a project-relative file to export the current condition to. Tracked in CoolantHeatConditionFile. The three standard cooling types ship as ready-made files in HiNc-Resource (Resource/CoolantHeatCondition/StandardForcedAir.default.CoolantHeatCondition, StandardOilBasedCoolant.default.CoolantHeatCondition and StandardWaterSolubleCoolant.default.CoolantHeatCondition), so Browse Resource… starts populated like the workpiece-material picker — picking a shipped file is the cooling-type selection. Name / Note — read-only mirror of the loaded condition. Property fields (always visible, under Name / Note): Coolant Temperature (°C) — CoolantTemperature_C. Flood Convection Coefficient (W/(m²·K)) — CoolantConvectionCoefficient_Wdm2K, min: 0. Mist / Flood Ratio — MistFloodConvectionRatio, min: 0. Off (Air) Convection Coefficient (W/(m²·K)) — OffConvectionCoefficient_Wdm2K, min: 0. Both leaves, with no project open: every control is disabled and a “no project — open one first” caption is shown. The panel fetches the snapshot itself on mount and gates on its hasEquipment flag, so the tree host holds no state for either leaf. Behavior File-based conditions (WorkpieceMaterial pattern). Picking a .CoolantHeatCondition file installs it as the whole condition (XFactory.GenByFile); Save As… exports the current values and renames the condition after the file (IPreferredFileName). While CoolantHeatConditionFile is set, the project save externalizes the condition asrelPath and regenerates the side-file (a resource pick is copied into the project on save); with no file the bare inline shape is kept byte-compatible. Coefficient edits tune this project's copy. The static presets on CoolantHeatCondition (StandardPresets / ApplyPreset / MatchStandardPreset) are the API-side source the shipped files are authored from. The file row's Clear entry does nothing here. FilePathInput reports a clear by emitting update:modelValue(null), and this panel binds the widget's value one-way and listens only for picked — so the entry is rendered, is clickable while a file is set, and drops nothing. Clearing the tracked file is therefore not reachable from this leaf at all; the reference changes only by loading another file or by a Save As. The .default marker never survives a user save. The shipped resource files carry a .default ownership marker in their names. The Save As… prompt strips it from its prefill, and the controller strips it again from the name it stamps on the condition, so a user save cannot mint a file that masquerades as a shipped default. The “not attached” badge is unreachable, and the lazy creation behind it never fires. SetupEquipment initializes CoolantHeatCondition at its declaration and nothing assigns null to it — the project-XML read replaces the instance only when the element is present — so the controller's hasCoolant, which is a null test on that property, is true whenever a project is open. The badge is therefore rendered only in the no-equipment case the panel already covers with its own caption, and the null branch each scalar PUT carries is defensive rather than reached. What a fresh project actually carries is the class defaults, which are the water-soluble preset's values. Celsius is the wire format. CoolantHeatCondition stores Kelvin internally but exposes _C accessors that handle the conversion, and the DTO carries Celsius. Finite values only. Every field handler drops a null or non-finite entry before any request is made, so Infinity never reaches these endpoints even though the numeric widget can parse it. Ambient and coolant temperatures accept negatives (e.g. -40 °C for cryogenic coolant); the three convection fields are clamped to min: 0. The run sees it at once. The ambient-temperature write, all four condition scalars and the file load each end in the project service's ForwardSetupEnvironmentToExecution, which stamps the ambient temperature and the condition reference onto the runtime equipment face — including the lazily created condition, which otherwise would exist only on the authored side. Source Code Path See HiNC App Anatomy for git repository links. Web Application HiNC-2025-webservice (Quasar CLI SPA): wwwroot-src/src/components/controlTree/ThermalConditionPanel.vue — the one panel both leaves share, branching on the node's last role-path segment: Ambient Temperature renders the single temperature field, Coolant the not-attached badge, the file row, the read-only Name / Note and the four property fields. wwwroot-src/src/components/controlTree/useControlTreeHost.ts — declares the two ThermalCondition leaves (equipment/background, equipment/coolant) under the General Setup group, with no host-level init state. wwwroot-src/src/components/controlTree/itemTypes.ts — registers the ThermalCondition item type against that panel: no child tree, no geometry-cache chain. wwwroot-src/src/components/widgets/FilePathInput.vue — the file row widget: Browse… / Browse Resource… (opening at the CoolantHeatCondition resource subfolder) / Clear. wwwroot-src/src/components/widgets/NumericInput.vue — the numeric field used by every value on both leaves, and the source of the min: 0 clamp on the three convection fields. wwwroot-src/src/api/backgroundCoolant.ts — typed client for /api/mech/background-coolant/*: the flat snapshot, the load / save-as pair, and the five scalar PUTs. wwwroot-src/src/router/routes.ts — carries the equipment/background-coolant redirect, which lands on general-setup?tree=equipment/background. Mech/BackgroundCoolantController.cs — REST surface at /api/mech/background-coolant over the authored equipment face (the route, the PUT path and the snapshot field keep their legacy background wire names; only the C# member behind them is renamed): GET / — flat snapshot { hasEquipment, backgroundTemperature_C, hasCoolant, coolantTemperature_C, coolantConvectionCoefficient_Wdm2K, mistFloodConvectionRatio, offConvectionCoefficient_Wdm2K, coolantName, coolantNote, coolantHeatConditionFile }. POST /load, POST /save-as — { rootName, relFile }: install a .CoolantHeatCondition file / export the current condition. Both resolve the path under the named root and refuse anything that escapes it, and both record the result in CoolantHeatConditionFile as a project-relative path when it lands under the project. Save-as appends the extension when it is missing and renames the condition after the file (IPreferredFileName) with the .default marker stripped. PUT /background-temperature-c — set AmbientTemperature_C. PUT /coolant-temperature-c, PUT /coolant-convection-coefficient-wdm2k, PUT /mist-flood-convection-ratio, PUT /off-convection-coefficient-wdm2k — the four condition scalars, all through one helper that lazy-creates the condition when absent, writes it, and forwards to the runtime face. HiAPI Engine HiMech/Physics/CoolantHeatCondition.cs — the model: Kelvin storage with _C accessors, the flood / mist-ratio / off convection coefficients, Name and Note with PreferredFileName, and the StandardPresets / ApplyPreset / MatchStandardPreset statics behind the shipped resource files. HiMech/Machining/MachiningEquipmentUtils/SetupEquipment.cs — the authored equipment face that owns the ambient temperature, the condition and its file reference, and externalizes the condition to the side-file when that reference is set. See Also Spindle Capability — sibling equipment editor, editing the same authored equipment face. Coolant (manual) — the end-user task: picking a cooling type in the application. Coolant Model — what the values on this panel mean, which one a running program applies, and how the condition is stored." }, "anatomy/general-setup/controller/brand-matrix.html": { "href": "anatomy/general-setup/controller/brand-matrix.html", @@ -192,7 +192,7 @@ "anatomy/general-setup/controller/machine/per-axis-tables.html": { "href": "anatomy/general-setup/controller/machine/per-axis-tables.html", "title": "Per-Axis Tables | HiAPI-C# 2025", - "summary": "Per-Axis Tables Four leaves of the Controller branch's machine plane are one table each, keyed on the machine's axes: Machine Limits (Stroke), Rapid Feedrates, Home / G28 Reference and Tool-Change Position. They live on the General Setup page at /general-setup under the Control-Tree ids equipment/controller/machine/limits, equipment/controller/machine/rapid, equipment/controller/machine/home and equipment/controller/machine/tool-change; none of them is gated by a snapshot flag, so every brand grows all four. Two components serve them — one panel behind the first three, discriminating on the id's last segment, and a second behind Tool-Change Position — and the differences between those two components are what this page is mostly about. Important Anatomy makes no claim that any id named here is stable across versions. The migration hop that keeps an older ?tree= value resolving is described in Tree Ids and Routes. Where the Rows Come From Every row on all four leaves is one axis of the runner's machine-axis configuration, read as AxisNames through the proxy-resolved dependency list. On all five brand presets that configuration is the brand parameter table itself: ControllerParameterTableBase declares IMachineAxisConfig alongside IStrokeLimitConfig, IRapidFeedrateConfig and IHomeMcConfig, so one object supplies both the row set and three of the four value sets. Which brand carries which table is Brand Matrix. The table's axis set is a single parameter row: the per-axis integer bucket under the brand's axis-type number, whose keys are the axis names and whose values are the AxisType — linear, rotary or spindle. Adding an axis therefore means adding a key to that one row, and exactly one surface on this branch reaches it. Neither panel here has an add-row or delete-row control. Both render a fixed header over onerelPath per axis and nothing else. The four per-axis routes behind them write one axis' value and nothing more: the caller names an axis, and the endpoint writes into the stroke-limit, rapid-rate, home or tool-change store under that name. None of them touches the axis-type row, so none of them changes which rows the next read returns. Parameters (Native) edits the axis-type row itself, and is the one place on the branch that widens the axis set: its Add / Set footer takes a free-text axis name, so the section Axis (integer), the brand's axis-type number, a name and a value of 0 linear, 1 rotary or 2 spindle adds an axis, which then appears on all four leaves. Its grid cannot — the per-axis columns are the union of the axis names already present, so a cell can be written only for an axis that exists — and its delete button removes a whole parameter row, every axis cell of one number at once, rather than one axis. Axes arrive from the machining chain. Whenever the active runner suit or the chain changes, the project service re-binds the suit and calls ConfigureByMachiningChain(API), which walks the chain's axis codes and their transformers: a rotating transformer writes the axis as rotary — and, on a brand parameter table, writes its reference position as 0 deg and its rapid rate as 36000 deg/min — any other transformer writes the axis as linear, and every chain axis whose reference position is still unset is seeded to 0. That is the mechanism behind the description above the Home / G28 Reference table, \"Axes without a value are seeded to 0 when a machine tool attaches.\" The stamp adds rows and never removes one. The generic axis configuration carried by the CSV and CL runner suits is cleared before the walk; a brand parameter table is not, and keeps every axis it already held. An axis dropped from the chain therefore keeps its rows on all four leaves, and no surface removes it individually. The three-axis default table every brand preset seeds is why a project with no machine tool attached still shows X, Y and Z. Two values are the exception, and only on a rotary chain axis of a brand table: that branch of the walk is unconditional, so it rewrites the axis' reference position to 0 deg and its rapid rate to 36000 deg/min whether or not one was stored. The walk re-runs on every suit re-bind, so an edited Home Position or Rapid Rate on a rotary axis is back at those two numbers once the chain or the active suit changes. A linear axis' values, and every value on an axis the chain does not carry, are left untouched. The caption below the first three tables records the row half of that: \"Axis rows follow the Machine Tool chain; they cannot be added here.\" Where the chain itself is edited is Machine Tool. The Value Columns Each leaf renders the axis column, its own value column or columns, and a unit column. Leaf Value columns Empty cell means Machine Limits (Stroke) + Limit, − Limit no limit set for that axis and side Rapid Feedrates Rapid Rate never empty — see below Home / G28 Reference Home Position no reference position stored Tool-Change Position Stays put, Position see Stays Put The stroke-limit and home readers return an optional value and hand null straight through, so an unset cell is blank. The rapid reader does not: it returns the stored rate, or — when the axis has no rate of its own — the base class's fixed default, 20000 mm/min for a linear axis and 36000 deg/min for a rotary one. So a Rapid Rate cell is always a number, and a number in it is not proof that the axis has a row. A table cloned fresh from a brand's preset seed decides what the three leaves then open on, and all four brand defaults agree in shape: a linear X, Y and Z, a reference position of 0 on each, and a rapid rate per axis — and no stroke limit at all. Machine Limits therefore opens entirely blank on every brand, while Rapid Feedrates and Home / G28 Reference open populated. Whether a brand switch clones a fresh table or keeps the project's own is Machine and Controller Plane. The Unit Column The unit column's header is the translated label Unit; its cell text is not translated and does not come from the server. Each panel computes it in the browser from the row's rotary flag, using literal strings: Leaf Linear axis Rotary axis Machine Limits (Stroke) mm deg Rapid Feedrates mm/min deg/min Home / G28 Reference mm deg Tool-Change Position mm deg The flag itself is server-side, and it is the axis type rather than a separate setting: an axis stored as rotary or as spindle reports rotary, so a spindle-mode axis is labelled in degrees. The unit is a label, not a conversion. The base class writes a linear and a rotary rapid rate into the same per-axis cell and reads them back through the same lookup, differing only in the default returned when the cell is absent; the stroke-limit and home accessors are equally unit-blind. Nothing on these three leaves converts, so their numbers are the raw stored numbers, and the same values appear in Parameters (Native) under the brand's own parameter number: Role Fanuc, Mazak Syntec Siemens Heidenhain Axis type — the row set 1006 1006 30300 400 Reference position (home) 1240 1240 34010 410 Positive stroke limit 1300 1300 36100 420 Negative stroke limit 1320 1320 36110 430 Rapid rate 1420 1420 32000 1010 Mazak shares the Fanuc column because the Mazak preset carries the Fanuc parameter-table proxy; Siemens spends its rapid-rate role on the max-axis-velocity machine datum. Tool-Change Position is the exception on both counts: its values live on ToolingMcConfig, a plain runner-owned dependency rather than a parameter table, so they appear in no native form at all and a brand apply returns them to the preset defaults — see Machine and Controller Plane. Stays Put, and the Sentinel Behind It IToolingMcConfig stores one number per axis, and the contract gives one number a second meaning: NaN means the axis stays where it is during a tool change. The read splits that back into two fields — a stored NaN becomes the Stays put flag with no position, anything else becomes the position — and the panel renders the flag as a checkbox and the position as a numeric field disabled while the box is ticked. Writing goes the same way round. Ticking the box sends the stay flag and the reader writes NaN. Unticking it sends a position, and because the panel clears its own cell when the box is ticked, the position it sends on the way back is 0 — so unticking parks the axis at machine zero rather than restoring what was there before. A third state exists and is not the sentinel: an axis with no entry in the map at all. Its box is unticked and its Position cell blank, because the reader reports no position and no stay. At run time the two are indistinguishable — the tool-change motion overlays only those axes that carry a number and are not NaN onto the current pose, and leaves every other axis alone. So the machine stays put either way; the tick mark distinguishes only how that was recorded. The overlay has a vocabulary of its own, narrower than the table. X, Y and Z always take part; every other axis takes part only while the machine declares it rotary. A linear axis outside those three is stored, shown and editable on this leaf, and never moved. The preset default is exactly this mixture: X and Y carry the sentinel, Z carries 0, and no rotary axis carries an entry, which is why a rotary axis usually opens unticked and blank. Above the table sits Tool-change mechanism time, a single field in seconds bound to ToolingTime. It becomes the duration of the tool change step the runner emits, and it is the changer mechanism alone — the axis travel to and from the position is timed separately from the positions in the table. It is 0 on every brand preset, and it is written into the runner file only when non-zero. One Reader, Two Readings of Its Presence Flag All four reads answer the same shape: a present flag plus one row per axis. present reports whether the backing configuration resolved — stroke limit, rapid feedrate, home or tool change — and it is computed independently of the rows. Each reader builds the row list from the axis set whether or not that configuration resolved, and fills the value cells from an optional reference, so a missing configuration yields blank limit and home cells, a 0 rapid rate, and rows all the same. The two components read the answer differently, and this is the sharpest divergence between them. The axis-table panel discards present entirely. Its typed reader parses the flag; the panel assigns only the rows. Its second empty layer keys on the row count instead: with no axes it shows \"No machine axes yet — these rows are driven by the Machine Tool chain (MechBuilder). Attach a machine tool to edit per-axis values.\", and with axes it renders the table whatever the flag said. The tool-change panel reads present and, when it is false, shows \"No tool-change config on the active runner.\" What that costs: a runner that has axes but no stroke-limit, rapid-feedrate or home configuration renders a full, editable table of blank or zero cells, and every commit fails with a toast naming the missing dependency instead of the panel saying the table is absent. On the five shipped brand presets the state cannot arise, because the one object that supplies the axis set supplies all three configurations too. The reachable case is the mirror one, and it reaches the two panels differently: deleting the axis-type parameter row from Parameters (Native) empties the axis set, and the three axis-table leaves fall to the no-axes line while Tool-Change Position keeps its rows, because its reader falls back to the tool-change configuration's own axis keys when the axis set is empty. Rows recovered that way are reported as linear whatever they are. The tool-change flag itself is never false on a shipped preset: all five carry the tool-change configuration as a plain entry, so its empty line is reachable only on a hand-built or file-loaded runner. Above both layers sits the shared no-runner guard every leaf of the branch carries; it, and the commit, rollback and toast rules the four leaves share with the rest of the branch, are Editing Contract. Editing a Cell Numeric cells are the shared numeric field, so a value commits on blur or on Enter and never per keystroke — its full contract is Numeric Input. The Stays put checkbox commits on the click. Three details govern how these four leaves commit: The writes are per cell, not per row. Editing + Limit sends that side alone, and the endpoint leaves a side it was not sent unchanged. The branch's row-shaped editors do not agree on this: a tool-offset or work-coordinate edit resends the whole row, while Parameters (Native) writes one axis cell at a time as these four do. Clearing a cell writes nothing. An emptied field parses to null and the handler returns before the request, so the box is left blank on screen while the stored number stands, and the number returns when the panel is remounted by selecting another node and coming back. There is consequently no way to unset a stroke limit or a reference position from these panels; the only surface that removes one is the native leaf's whole-row delete. No cell is bounded. None of the four tables passes a minimum or a maximum to its fields, so a negative limit or a negative rapid rate is accepted and stored. The mechanism time is the one bounded field on the four leaves, at zero or above. What the Values Do When a Program Plays The stroke limits are checked at each played step against the chain's current machine pose while the session's stroke-limit check is on; a position past a configured limit is reported as a stroke-limit validation error anchored to that step, and pauses the player when pause-on-failure is set. The check walks a fixed axis vocabulary — X, Y and Z from the machine point, A, B and C from its orientation — so a limit stored against any other axis name is kept and shown here but never tested. Rapid-traverse timing has the same shape and the same six names: a G00 move is timed axis-by-axis at each axis' rate and takes the slowest, falling back to the same 20000 mm/min and 36000 deg/min defaults when no configuration answers. The reference positions reach further, but only at the start. The initializer that sets the machine pose at the first block writes every declared axis, reading each axis' stored reference and falling back to 0 for one that has none. The G28 reference return reads the same store through a narrower window: X, Y and Z for its linear stage, and A, B or C for its rotary stage — and a rotary letter only while the machine declares that axis rotary and a reference position is stored for it, an unconfigured one being reported as a validation error instead. So an axis outside the six canonical names still carries its stored reference into the pose at the first block, while its stroke limit, its rapid rate and its G28 return are all inert. Layout General Setup Control Tree — the left dock of /general-setup Controller Node Row Machine / Controller Group Row Machine Limits (Stroke) Node Row — equipment/controller/machine/limits Rapid Feedrates Node Row — equipment/controller/machine/rapid Home / G28 Reference Node Row — equipment/controller/machine/home Tool-Change Position Node Row — equipment/controller/machine/tool-change Editor Row — the panel of whichever node is selected Machine Limits (Stroke) / Rapid Feedrates / Home / G28 Reference Panel — one component, its role taken from the selected id's last segment Description Caption — \"Machine travel limits per axis (empty = no limit set). Motions beyond a limit raise a stroke-limit validation error.\", \"G00 rapid traverse rate per axis.\" or \"G28 first reference (home) machine coordinate per axis. Axes without a value are seeded to 0 when a machine tool attaches.\" Axis Table — dense, flat, bordered Header Row — Axis, then + Limit and − Limit, or Rapid Rate, or Home Position, then Unit Axis Row, one per axis Axis Name Label — bold, not editable Value Numeric Field, one per value column Unit Label — mm / deg, or mm/min / deg/min on Rapid Feedrates Footer Caption — \"Axis rows follow the Machine Tool chain; they cannot be added here.\" No-Axes Block — replaces the description, the table and the footer caption when the axis set is empty: a precision-manufacturing icon beside \"No machine axes yet — these rows are driven by the Machine Tool chain (MechBuilder). Attach a machine tool to edit per-axis values.\" Tool-Change Position Panel Tool-change mechanism time Numeric Field — suffixed s, minimum 0 Axis Table — dense, flat, bordered Header Row — Axis, Stays put, Position, Unit Axis Row, one per axis Axis Name Label — bold, not editable Stays put CheckBox Position Numeric Field — disabled while Stays put is ticked Unit Label — mm / deg Footer Caption — “Stays put” leaves the axis where it is during a tool change. No-Config Block — replaces the field, the table and the caption: \"No tool-change config on the active runner.\" Shared Empty State — replaces either panel's whole body while the snapshot reports no runner: \"No NC runner — load a project first.\" Source Code Path See HiNC App Anatomy for git repository links. Web Application HiNC-2025-webservice (Quasar CLI SPA): wwwroot-src/src/components/controlTree/SoftNcAxisTablePanel.vue — the panel behind the first three leaves: the role taken from the node id's last segment, the value columns and description per role, the unit strings computed from the row's rotary flag, the row-count empty layer that discards the read's presence flag, and the per-cell commit that returns on a cleared field. wwwroot-src/src/components/controlTree/SoftNcToolChangePanel.vue — the tool-change panel: the mechanism-time field, the Stays put checkbox that clears the position and sends 0 on the way back, the disabled position cell, and the presence-flag empty layer. wwwroot-src/src/components/controlTree/SoftNcEmptyState.vue — the shared no-runner line both panels open with. wwwroot-src/src/components/widgets/NumericInput.vue — the numeric cell: commit on blur or Enter, and the empty-text-to-null parse the panels reject. wwwroot-src/src/components/controlTree/softNcItemTypes.ts — the four node ids, their labels and label keys, and the two item types that bind them to the two panels. wwwroot-src/src/api/softNcRunner.ts — the four readers and their setters: the row shapes, the presence flag both panels receive, the per-side stroke-limit payload, and the stay-or-position tool-change payload. wwwroot-src/src/composables/useSoftNcRunner.ts — the shared runner snapshot the first empty layer reads. wwwroot-src/src/i18n/en/softNc.ts — the four node labels, the three descriptions, the column headers, the two footer captions and the two empty-state lines quoted above. wwwroot-src/src/i18n/en/common.ts — the shared Axis and Unit column headers. wwwroot-src/src/components/controlTree/SoftNcNativeParamsPanel.vue — the neighbouring leaf that edits the same parameter rows by number: the per-cell axis writes, the grid columns unioned from the existing axis names, the delete that drops a whole row, and the Add / Set footer whose free-text axis field is what widens the axis-type row. Mech/SoftNcRunnerController.cs — the REST surface: the chain-driven axis helper every reader builds its rows from, the four readers with their independently computed presence flags, the four per-axis writers that name an axis but never declare one, the native per-axis-integer route that does, the tool-change fallback to the tool-change configuration's own axis keys, the NaN sentinel write, and the rotary lookup the rapid write re-derives server-side. HiAPI Engine HiMech/NcParsers/Dependencys/ControllerParameterTableBase.cs — the one object behind three of the four leaves: the axis set as the keys of the axis-type row, the reference-position, rapid-rate and stroke-limit accessors over the per-axis buckets, the fixed rapid defaults, and the rotary configuration helper the chain walk calls, which writes the axis type, the reference position and the rapid rate together with no guard on the two values. HiMech/NcParsers/Dependencys/IMachineAxisConfig.cs — the axis contract and the axis-type enum whose rotary and spindle members both make a row rotary. HiMech/NcParsers/Dependencys/IStrokeLimitConfig.cs — the limit accessors, and the check itself with its fixed X/Y/Z and A/B/C vocabulary and its validation report. HiMech/NcParsers/Dependencys/IRapidFeedrateConfig.cs — the linear and rotary rate accessors. HiMech/NcParsers/Dependencys/IHomeMcConfig.cs — the reference-position accessors. HiMech/NcParsers/Dependencys/IToolingMcConfig.cs — the tool-change contract: the NaN sentinel and the mechanism time. HiMech/NcParsers/Dependencys/Generic/ToolingMcConfig.cs — the sole implementation: the per-axis map, the preset default of X and Y staying and Z at 0, and the serialization that omits a zero mechanism time. HiMech/NcParsers/Dependencys/Fanuc/FanucParameterTable.cs, HiMech/NcParsers/Dependencys/Syntec/SyntecParameterTable.cs, HiMech/NcParsers/Dependencys/Siemens/SiemensMachineDataTable.cs, HiMech/NcParsers/Dependencys/Heidenhain/HeidenhainParameterTable.cs — the parameter numbers in the table above and the three-axis default each brand opens on. HiMech/NcParsers/Dependencys/Fanuc/FanucParameterTableProxy.cs, HiMech/NcParsers/Dependencys/Syntec/SyntecParameterTableProxy.cs, HiMech/NcParsers/Dependencys/Siemens/SiemensMachineDataTableProxy.cs, HiMech/NcParsers/Dependencys/Heidenhain/HeidenhainParameterTableProxy.cs — the placeholders the brand presets actually carry: each clones its three-axis seed into the project's own dependency list when that list holds none, and resolves to the project's table when it does. HiMech/NcParsers/SoftNcRunner.cs — the chain walk that stamps axis codes, hands a rotary axis to the unconditional rotary helper on a brand table, and fills a missing reference position; and the five brand presets that decide which parameter table and which tool-change configuration a brand carries. HiNc/MachiningProcs/LocalProjectService.cs — where the chain walk is triggered from, why the generic axis configuration is cleared first and a brand table is not, and the per-step stroke-limit check that reads the limits through the proxy-resolved list. HiMech/MachiningProcs/MachiningSession.cs — the play loop that runs that check once per step and pauses on failure. HiMech/NcParsers/Semantics/LinearMotionUtil.cs — rapid-traverse timing: per-axis rates, the slowest axis, and the same six axis names the stroke check uses. HiMech/NcParsers/Initializers/HomeMcInitializer.cs — the reference positions written for every declared axis at the first block. HiMech/NcParsers/LogicSyntaxs/ReferenceReturnSyntax.cs — the G28 return: the three linear names it resolves a final position for, the three rotary letters it tests against the declared axes, and the validation error a rotary letter the machine has not declared raises. HiMech/NcParsers/LogicSyntaxs/ToolChangeMotionSyntax.cs — the overlay: X, Y and Z plus the declared rotary axes, of which only the ones carrying a non-NaN position move. HiMech/NcParsers/Semantics/ToolChangeSemantic.cs — the tool-change step that carries the mechanism time as its duration. See Also Machine and Controller Plane — the plane these four leaves sit on, and which half of the project each of their values is stored in Brand Matrix — why all four are ungated, and which table each brand resolves them through Editing Contract — the fetch, commit, rollback and empty-layer rules these panels share with the rest of the branch, and where they are recorded as departing from them" + "summary": "Per-Axis Tables Four leaves of the Controller branch's machine plane are one table each, keyed on the machine's axes: Machine Limits (Stroke), Rapid Feedrates, Home / G28 Reference and Tool-Change Position. They live on the General Setup page at /general-setup under the Control-Tree ids equipment/controller/machine/limits, equipment/controller/machine/rapid, equipment/controller/machine/home and equipment/controller/machine/tool-change; none of them is gated by a snapshot flag, so every brand grows all four. Two components serve them — one panel behind the first three, discriminating on the id's last segment, and a second behind Tool-Change Position — and the differences between those two components are what this page is mostly about. Important Anatomy makes no claim that any id named here is stable across versions. The migration hop that keeps an older ?tree= value resolving is described in Tree Ids and Routes. Where the Rows Come From Every row on all four leaves is one axis of the runner's machine-axis configuration, read as AxisNames through the proxy-resolved dependency list. On all five brand presets that configuration is the brand parameter table itself: ControllerParameterTableBase declares IMachineAxisConfig alongside IStrokeLimitConfig, IRapidFeedrateConfig and IHomeMcConfig, so one object supplies both the row set and three of the four value sets. Which brand carries which table is Brand Matrix. The table's axis set is a single parameter row: the per-axis integer bucket under the brand's axis-type number, whose keys are the axis names and whose values are the AxisType — linear, rotary or spindle. Adding an axis therefore means adding a key to that one row, and exactly one surface on this branch reaches it. Neither panel here has an add-row or delete-row control. Both render a fixed header over one per axis and nothing else. The four per-axis routes behind them write one axis' value and nothing more: the caller names an axis, and the endpoint writes into the stroke-limit, rapid-rate, home or tool-change store under that name. None of them touches the axis-type row, so none of them changes which rows the next read returns. Parameters (Native) edits the axis-type row itself, and is the one place on the branch that widens the axis set: its Add / Set footer takes a free-text axis name, so the section Axis (integer), the brand's axis-type number, a name and a value of 0 linear, 1 rotary or 2 spindle adds an axis, which then appears on all four leaves. Its grid cannot — the per-axis columns are the union of the axis names already present, so a cell can be written only for an axis that exists — and its delete button removes a whole parameter row, every axis cell of one number at once, rather than one axis. Axes arrive from the machining chain. Whenever the active runner suit or the chain changes, the project service re-binds the suit and calls ConfigureByMachiningChain(API), which walks the chain's axis codes and their transformers: a rotating transformer writes the axis as rotary — and, on a brand parameter table, writes its reference position as 0 deg and its rapid rate as 36000 deg/min — any other transformer writes the axis as linear, and every chain axis whose reference position is still unset is seeded to 0. That is the mechanism behind the description above the Home / G28 Reference table, \"Axes without a value are seeded to 0 when a machine tool attaches.\" The stamp adds rows and never removes one. The generic axis configuration carried by the CSV and CL runner suits is cleared before the walk; a brand parameter table is not, and keeps every axis it already held. An axis dropped from the chain therefore keeps its rows on all four leaves, and no surface removes it individually. The three-axis default table every brand preset seeds is why a project with no machine tool attached still shows X, Y and Z. Two values are the exception, and only on a rotary chain axis of a brand table: that branch of the walk is unconditional, so it rewrites the axis' reference position to 0 deg and its rapid rate to 36000 deg/min whether or not one was stored. The walk re-runs on every suit re-bind, so an edited Home Position or Rapid Rate on a rotary axis is back at those two numbers once the chain or the active suit changes. A linear axis' values, and every value on an axis the chain does not carry, are left untouched. The caption below the first three tables records the row half of that: \"Axis rows follow the Machine Tool chain; they cannot be added here.\" Where the chain itself is edited is Machine Tool. The Value Columns Each leaf renders the axis column, its own value column or columns, and a unit column. Leaf Value columns Empty cell means Machine Limits (Stroke) + Limit, − Limit no limit set for that axis and side Rapid Feedrates Rapid Rate never empty — see below Home / G28 Reference Home Position no reference position stored Tool-Change Position Stays put, Position see Stays Put The stroke-limit and home readers return an optional value and hand null straight through, so an unset cell is blank. The rapid reader does not: it returns the stored rate, or — when the axis has no rate of its own — the base class's fixed default, 20000 mm/min for a linear axis and 36000 deg/min for a rotary one. So a Rapid Rate cell is always a number, and a number in it is not proof that the axis has a row. A table cloned fresh from a brand's preset seed decides what the three leaves then open on, and all four brand defaults agree in shape: a linear X, Y and Z, a reference position of 0 on each, and a rapid rate per axis — and no stroke limit at all. Machine Limits therefore opens entirely blank on every brand, while Rapid Feedrates and Home / G28 Reference open populated. Whether a brand switch clones a fresh table or keeps the project's own is Machine and Controller Plane. The Unit Column The unit column's header is the translated label Unit; its cell text is not translated and does not come from the server. Each panel computes it in the browser from the row's rotary flag, using literal strings: Leaf Linear axis Rotary axis Machine Limits (Stroke) mm deg Rapid Feedrates mm/min deg/min Home / G28 Reference mm deg Tool-Change Position mm deg The flag itself is server-side, and it is the axis type rather than a separate setting: an axis stored as rotary or as spindle reports rotary, so a spindle-mode axis is labelled in degrees. The unit is a label, not a conversion. The base class writes a linear and a rotary rapid rate into the same per-axis cell and reads them back through the same lookup, differing only in the default returned when the cell is absent; the stroke-limit and home accessors are equally unit-blind. Nothing on these three leaves converts, so their numbers are the raw stored numbers, and the same values appear in Parameters (Native) under the brand's own parameter number: Role Fanuc, Mazak Syntec Siemens Heidenhain Axis type — the row set 1006 1006 30300 400 Reference position (home) 1240 1240 34010 410 Positive stroke limit 1300 1300 36100 420 Negative stroke limit 1320 1320 36110 430 Rapid rate 1420 1420 32000 1010 Mazak shares the Fanuc column because the Mazak preset carries the Fanuc parameter-table proxy; Siemens spends its rapid-rate role on the max-axis-velocity machine datum. Tool-Change Position is the exception on both counts: its values live on ToolingMcConfig, a plain runner-owned dependency rather than a parameter table, so they appear in no native form at all and a brand apply returns them to the preset defaults — see Machine and Controller Plane. Stays Put, and the Sentinel Behind It IToolingMcConfig stores one number per axis, and the contract gives one number a second meaning: NaN means the axis stays where it is during a tool change. The read splits that back into two fields — a stored NaN becomes the Stays put flag with no position, anything else becomes the position — and the panel renders the flag as a checkbox and the position as a numeric field disabled while the box is ticked. Writing goes the same way round. Ticking the box sends the stay flag and the reader writes NaN. Unticking it sends a position, and because the panel clears its own cell when the box is ticked, the position it sends on the way back is 0 — so unticking parks the axis at machine zero rather than restoring what was there before. A third state exists and is not the sentinel: an axis with no entry in the map at all. Its box is unticked and its Position cell blank, because the reader reports no position and no stay. At run time the two are indistinguishable — the tool-change motion overlays only those axes that carry a number and are not NaN onto the current pose, and leaves every other axis alone. So the machine stays put either way; the tick mark distinguishes only how that was recorded. The overlay has a vocabulary of its own, narrower than the table. X, Y and Z always take part; every other axis takes part only while the machine declares it rotary. A linear axis outside those three is stored, shown and editable on this leaf, and never moved. The preset default is exactly this mixture: X and Y carry the sentinel, Z carries 0, and no rotary axis carries an entry, which is why a rotary axis usually opens unticked and blank. Above the table sits Tool-change mechanism time, a single field in seconds bound to ToolingTime. It becomes the duration of the tool change step the runner emits, and it is the changer mechanism alone — the axis travel to and from the position is timed separately from the positions in the table. It is 0 on every brand preset, and it is written into the runner file only when non-zero. One Reader, Two Readings of Its Presence Flag All four reads answer the same shape: a present flag plus one row per axis. present reports whether the backing configuration resolved — stroke limit, rapid feedrate, home or tool change — and it is computed independently of the rows. Each reader builds the row list from the axis set whether or not that configuration resolved, and fills the value cells from an optional reference, so a missing configuration yields blank limit and home cells, a 0 rapid rate, and rows all the same. The two components read the answer differently, and this is the sharpest divergence between them. The axis-table panel discards present entirely. Its typed reader parses the flag; the panel assigns only the rows. Its second empty layer keys on the row count instead: with no axes it shows \"No machine axes yet — these rows are driven by the Machine Tool chain (MechBuilder). Attach a machine tool to edit per-axis values.\", and with axes it renders the table whatever the flag said. The tool-change panel reads present and, when it is false, shows \"No tool-change config on the active runner.\" What that costs: a runner that has axes but no stroke-limit, rapid-feedrate or home configuration renders a full, editable table of blank or zero cells, and every commit fails with a toast naming the missing dependency instead of the panel saying the table is absent. On the five shipped brand presets the state cannot arise, because the one object that supplies the axis set supplies all three configurations too. The reachable case is the mirror one, and it reaches the two panels differently: deleting the axis-type parameter row from Parameters (Native) empties the axis set, and the three axis-table leaves fall to the no-axes line while Tool-Change Position keeps its rows, because its reader falls back to the tool-change configuration's own axis keys when the axis set is empty. Rows recovered that way are reported as linear whatever they are. The tool-change flag itself is never false on a shipped preset: all five carry the tool-change configuration as a plain entry, so its empty line is reachable only on a hand-built or file-loaded runner. Above both layers sits the shared no-runner guard every leaf of the branch carries; it, and the commit, rollback and toast rules the four leaves share with the rest of the branch, are Editing Contract. Editing a Cell Numeric cells are the shared numeric field, so a value commits on blur or on Enter and never per keystroke — its full contract is Numeric Input. The Stays put checkbox commits on the click. Three details govern how these four leaves commit: The writes are per cell, not per row. Editing + Limit sends that side alone, and the endpoint leaves a side it was not sent unchanged. The branch's row-shaped editors do not agree on this: a tool-offset or work-coordinate edit resends the whole row, while Parameters (Native) writes one axis cell at a time as these four do. Clearing a cell writes nothing. An emptied field parses to null and the handler returns before the request, so the box is left blank on screen while the stored number stands, and the number returns when the panel is remounted by selecting another node and coming back. There is consequently no way to unset a stroke limit or a reference position from these panels; the only surface that removes one is the native leaf's whole-row delete. No cell is bounded. None of the four tables passes a minimum or a maximum to its fields, so a negative limit or a negative rapid rate is accepted and stored. The mechanism time is the one bounded field on the four leaves, at zero or above. What the Values Do When a Program Plays The stroke limits are checked at each played step against the chain's current machine pose while the session's stroke-limit check is on; a position past a configured limit is reported as a stroke-limit validation error anchored to that step, and pauses the player when pause-on-failure is set. The comparison carries a small tolerance (Tolerance), so an axis parked exactly on its limit is not reported. The rotary limits also steer the tilt solves: when a G53.1, G68.2, CYCLE800, PLANE SPATIAL or LN posture has its nearest rotary solution outside the travel, the solve takes the admissible branch nearest the entry instead of commanding a posture the machine cannot take. A project that declared its travel only in the legacy machine-limits boxes gets those ends copied into this table on load, for the axes carrying no end here. The check walks a fixed axis vocabulary — X, Y and Z from the machine point, A, B and C from its orientation — so a limit stored against any other axis name is kept and shown here but never tested. Rapid-traverse timing has the same shape and the same six names: a G00 move is timed axis-by-axis at each axis' rate and takes the slowest, falling back to the same 20000 mm/min and 36000 deg/min defaults when no configuration answers. The reference positions reach further, but only at the start. The initializer that sets the machine pose at the first block writes every declared axis, reading each axis' stored reference and falling back to 0 for one that has none. The G28 reference return reads the same store through a narrower window: X, Y and Z for its linear stage, and A, B or C for its rotary stage — and a rotary letter only while the machine declares that axis rotary and a reference position is stored for it, an unconfigured one being reported as a validation error instead. So an axis outside the six canonical names still carries its stored reference into the pose at the first block, while its stroke limit, its rapid rate and its G28 return are all inert. Layout General Setup Control Tree — the left dock of /general-setup Controller Node Row Machine / Controller Group Row Machine Limits (Stroke) Node Row — equipment/controller/machine/limits Rapid Feedrates Node Row — equipment/controller/machine/rapid Home / G28 Reference Node Row — equipment/controller/machine/home Tool-Change Position Node Row — equipment/controller/machine/tool-change Editor Row — the panel of whichever node is selected Machine Limits (Stroke) / Rapid Feedrates / Home / G28 Reference Panel — one component, its role taken from the selected id's last segment Description Caption — \"Machine travel limits per axis (empty = no limit set). Motions beyond a limit raise a stroke-limit validation error.\", \"G00 rapid traverse rate per axis.\" or \"G28 first reference (home) machine coordinate per axis. Axes without a value are seeded to 0 when a machine tool attaches.\" Axis Table — dense, flat, bordered Header Row — Axis, then + Limit and − Limit, or Rapid Rate, or Home Position, then Unit Axis Row, one per axis Axis Name Label — bold, not editable Value Numeric Field, one per value column Unit Label — mm / deg, or mm/min / deg/min on Rapid Feedrates Footer Caption — \"Axis rows follow the Machine Tool chain; they cannot be added here.\" No-Axes Block — replaces the description, the table and the footer caption when the axis set is empty: a precision-manufacturing icon beside \"No machine axes yet — these rows are driven by the Machine Tool chain (MechBuilder). Attach a machine tool to edit per-axis values.\" Tool-Change Position Panel Tool-change mechanism time Numeric Field — suffixed s, minimum 0 Axis Table — dense, flat, bordered Header Row — Axis, Stays put, Position, Unit Axis Row, one per axis Axis Name Label — bold, not editable Stays put CheckBox Position Numeric Field — disabled while Stays put is ticked Unit Label — mm / deg Footer Caption — “Stays put” leaves the axis where it is during a tool change. No-Config Block — replaces the field, the table and the caption: \"No tool-change config on the active runner.\" Shared Empty State — replaces either panel's whole body while the snapshot reports no runner: \"No NC runner — load a project first.\" Source Code Path See HiNC App Anatomy for git repository links. Web Application HiNC-2025-webservice (Quasar CLI SPA): wwwroot-src/src/components/controlTree/SoftNcAxisTablePanel.vue — the panel behind the first three leaves: the role taken from the node id's last segment, the value columns and description per role, the unit strings computed from the row's rotary flag, the row-count empty layer that discards the read's presence flag, and the per-cell commit that returns on a cleared field. wwwroot-src/src/components/controlTree/SoftNcToolChangePanel.vue — the tool-change panel: the mechanism-time field, the Stays put checkbox that clears the position and sends 0 on the way back, the disabled position cell, and the presence-flag empty layer. wwwroot-src/src/components/controlTree/SoftNcEmptyState.vue — the shared no-runner line both panels open with. wwwroot-src/src/components/widgets/NumericInput.vue — the numeric cell: commit on blur or Enter, and the empty-text-to-null parse the panels reject. wwwroot-src/src/components/controlTree/softNcItemTypes.ts — the four node ids, their labels and label keys, and the two item types that bind them to the two panels. wwwroot-src/src/api/softNcRunner.ts — the four readers and their setters: the row shapes, the presence flag both panels receive, the per-side stroke-limit payload, and the stay-or-position tool-change payload. wwwroot-src/src/composables/useSoftNcRunner.ts — the shared runner snapshot the first empty layer reads. wwwroot-src/src/i18n/en/softNc.ts — the four node labels, the three descriptions, the column headers, the two footer captions and the two empty-state lines quoted above. wwwroot-src/src/i18n/en/common.ts — the shared Axis and Unit column headers. wwwroot-src/src/components/controlTree/SoftNcNativeParamsPanel.vue — the neighbouring leaf that edits the same parameter rows by number: the per-cell axis writes, the grid columns unioned from the existing axis names, the delete that drops a whole row, and the Add / Set footer whose free-text axis field is what widens the axis-type row. Mech/SoftNcRunnerController.cs — the REST surface: the chain-driven axis helper every reader builds its rows from, the four readers with their independently computed presence flags, the four per-axis writers that name an axis but never declare one, the native per-axis-integer route that does, the tool-change fallback to the tool-change configuration's own axis keys, the NaN sentinel write, and the rotary lookup the rapid write re-derives server-side. HiAPI Engine HiMech/NcParsers/Dependencys/ControllerParameterTableBase.cs — the one object behind three of the four leaves: the axis set as the keys of the axis-type row, the reference-position, rapid-rate and stroke-limit accessors over the per-axis buckets, the fixed rapid defaults, and the rotary configuration helper the chain walk calls, which writes the axis type, the reference position and the rapid rate together with no guard on the two values. HiMech/NcParsers/Dependencys/IMachineAxisConfig.cs — the axis contract and the axis-type enum whose rotary and spindle members both make a row rotary. HiMech/NcParsers/Dependencys/IStrokeLimitConfig.cs — the limit accessors, and the check itself with its fixed X/Y/Z and A/B/C vocabulary and its validation report. HiMech/NcParsers/Dependencys/IRapidFeedrateConfig.cs — the linear and rotary rate accessors. HiMech/NcParsers/Dependencys/IHomeMcConfig.cs — the reference-position accessors. HiMech/NcParsers/Dependencys/IToolingMcConfig.cs — the tool-change contract: the NaN sentinel and the mechanism time. HiMech/NcParsers/Dependencys/Generic/ToolingMcConfig.cs — the sole implementation: the per-axis map, the preset default of X and Y staying and Z at 0, and the serialization that omits a zero mechanism time. HiMech/NcParsers/Dependencys/Fanuc/FanucParameterTable.cs, HiMech/NcParsers/Dependencys/Syntec/SyntecParameterTable.cs, HiMech/NcParsers/Dependencys/Siemens/SiemensMachineDataTable.cs, HiMech/NcParsers/Dependencys/Heidenhain/HeidenhainParameterTable.cs — the parameter numbers in the table above and the three-axis default each brand opens on. HiMech/NcParsers/Dependencys/Fanuc/FanucParameterTableProxy.cs, HiMech/NcParsers/Dependencys/Syntec/SyntecParameterTableProxy.cs, HiMech/NcParsers/Dependencys/Siemens/SiemensMachineDataTableProxy.cs, HiMech/NcParsers/Dependencys/Heidenhain/HeidenhainParameterTableProxy.cs — the placeholders the brand presets actually carry: each clones its three-axis seed into the project's own dependency list when that list holds none, and resolves to the project's table when it does. HiMech/NcParsers/SoftNcRunner.cs — the chain walk that stamps axis codes, hands a rotary axis to the unconditional rotary helper on a brand table, and fills a missing reference position; and the five brand presets that decide which parameter table and which tool-change configuration a brand carries. HiNc/MachiningProcs/LocalProjectService.cs — where the chain walk is triggered from, why the generic axis configuration is cleared first and a brand table is not, and the per-step stroke-limit check that reads the limits through the proxy-resolved list. HiMech/MachiningProcs/MachiningSession.cs — the play loop that runs that check once per step and pauses on failure. HiMech/NcParsers/Semantics/LinearMotionUtil.cs — rapid-traverse timing: per-axis rates, the slowest axis, and the same six axis names the stroke check uses. HiMech/NcParsers/Initializers/HomeMcInitializer.cs — the reference positions written for every declared axis at the first block. HiMech/NcParsers/LogicSyntaxs/ReferenceReturnSyntax.cs — the G28 return: the three linear names it resolves a final position for, the three rotary letters it tests against the declared axes, and the validation error a rotary letter the machine has not declared raises. HiMech/NcParsers/LogicSyntaxs/ToolChangeMotionSyntax.cs — the overlay: X, Y and Z plus the declared rotary axes, of which only the ones carrying a non-NaN position move. HiMech/NcParsers/Semantics/ToolChangeSemantic.cs — the tool-change step that carries the mechanism time as its duration. See Also Machine and Controller Plane — the plane these four leaves sit on, and which half of the project each of their values is stored in Brand Matrix — why all four are ungated, and which table each brand resolves them through Editing Contract — the fetch, commit, rollback and empty-layer rules these panels share with the rest of the branch, and where they are recorded as departing from them" }, "anatomy/general-setup/controller/machine/program-reading.html": { "href": "anatomy/general-setup/controller/machine/program-reading.html", @@ -247,7 +247,7 @@ "anatomy/general-setup/index.html": { "href": "anatomy/general-setup/index.html", "title": "General Setup Page | HiAPI-C# 2025", - "summary": "General Setup Page General Setup is the equipment page at /general-setup. It is one of the two Control-Tree pages: the left dock names every piece of equipment in the project and edits whatever is selected, and the canvas on the right shows all of it at once. Selection rides the URL as ?tree=equipment/…, so any branch of it is a link. The tree's one root is a pure Group stem at equipment, selectable in its own right: it renders an orientation panel listing the equipment items beneath it. The page renders three columns in nested splitters — the Control-Tree dock, the content column, and the equipment canvas. The dock carries two stacked rows: the tree above, and below it the editor panel of whichever node is selected. The content column holds a second, wider view of the same selection, mounted only for the item types that register one — on this page the spindle branch and nothing else — while every other selection leaves it showing its empty hint. Column widths are device-local, and the dock aligns with the Execution page's so the two tree pages feel like one application. Ordered as the page builds its equipment children. Pages Machine Tool — The kinematic chain the whole scene hangs from, and the standalone route that loads and previews it Spindle Capability — The spindle envelope: thermal condition, gear shift, dry run, power and torque Background / Coolant — The two scene branches that are not machine parts: the backdrop and the coolant model Fixture — What holds the workpiece, its geometry and the two anchors that place it Workpiece — Raw and target geometry, the anchors that locate them, the mesh, and the material Controller — The SoftNcRunner-native controller branch: its two planes, the brand matrix behind which nodes appear at all, and the contract every leaf edits by Hidden Controller Branches — The two runner-suit nodes a fresh installation never builds, the device-local checkboxes that reveal them, and the second kind of invisibility a link cannot undo A bookmark to the retired /controller address — the Legacy Controller page, which edited the deprecating HardNcEnv model rather than the runner — now redirects here and lands on the Controller branch. See Also Execution Page — the other Control-Tree page, and the one this was split out of Tool House Page — the third equipment surface, a tab page rather than a tree page Main Panel — the shell whose Page menu reaches this route Control Tree — the engine behind this page's tree: how a branch is built, rebuilt and selected Controller Branch — the branch this page hosts whose node set changes with the controller brand Hidden Controller Branches — the two equipment nodes this page withholds until a preference or a link asks for them Legacy Controller Model (HardNcEnv) — the deprecating HardNcEnv model the project still carries beside the runner, what it shares with the Controller branch, and the three settings that retire with it rather than gaining an editor in the equipment tree" + "summary": "General Setup Page General Setup is the equipment page at /general-setup. It is one of the two Control-Tree pages: the left dock names every piece of equipment in the project and edits whatever is selected, and the canvas on the right shows all of it at once. Selection rides the URL as ?tree=equipment/…, so any branch of it is a link. The tree's one root is a pure Group stem at equipment, selectable in its own right: it renders an orientation panel listing the equipment items beneath it. The page renders three columns in nested splitters — the Control-Tree dock, the content column, and the equipment canvas. The dock carries two stacked rows: the tree above, and below it the editor panel of whichever node is selected. The content column holds a second, wider view of the same selection, mounted only for the item types that register one — on this page the spindle branch and nothing else — while every other selection leaves it showing its empty hint. Column widths are device-local, and the dock aligns with the Execution page's so the two tree pages feel like one application. Ordered as the page builds its equipment children. Pages Machine Tool — The kinematic chain the whole scene hangs from, and the standalone route that loads and previews it Spindle Capability — The spindle envelope: thermal condition, gear shift, dry run, power and torque Environment: Ambient Temperature / Coolant — The Environment root's two thermal leaves, the ones that are not machine parts: the ambient (shop) temperature the thermal model starts from, and the coolant model Fixture — What holds the workpiece, its geometry and the two anchors that place it Workpiece — Raw and target geometry, the anchors that locate them, the mesh, and the material Controller — The SoftNcRunner-native controller branch: its two planes, the brand matrix behind which nodes appear at all, and the contract every leaf edits by Hidden Controller Branches — The two runner-suit nodes a fresh installation never builds, the device-local checkboxes that reveal them, and the second kind of invisibility a link cannot undo A bookmark to the retired /controller address — the Legacy Controller page, which edited the deprecating HardNcEnv model rather than the runner — now redirects here and lands on the Controller branch. See Also Execution Page — the other Control-Tree page, and the one this was split out of Tool House Page — the third equipment surface, a tab page rather than a tree page Main Panel — the shell whose Page menu reaches this route Control Tree — the engine behind this page's tree: how a branch is built, rebuilt and selected Controller Branch — the branch this page hosts whose node set changes with the controller brand Hidden Controller Branches — the two equipment nodes this page withholds until a preference or a link asks for them Legacy Controller Model (HardNcEnv) — the deprecating HardNcEnv model the project still carries beside the runner, what it shares with the Controller branch, and the three settings that retire with it rather than gaining an editor in the equipment tree" }, "anatomy/general-setup/machine-tool.html": { "href": "anatomy/general-setup/machine-tool.html", @@ -257,7 +257,7 @@ "anatomy/general-setup/spindle-capability.html": { "href": "anatomy/general-setup/spindle-capability.html", "title": "Spindle Capability | HiAPI-C# 2025", - "summary": "Spindle Capability The Spindle Capability editor is the equipment/spindle branch of the General Setup page's Control Tree (/general-setup?tree=equipment/spindle), the equipment child after Machine Tool. Two older paths redirect onto it: /spindle-capability/:tab?, whose tab segment maps straight onto one of the branch's five children, and /equipment/spindle. The menu bar carries no entry of its own for it — the Page menu reaches General Setup, and the tree reaches the branch. It edits SpindleCapability on the project's authored equipment face, SetupEquipment, reached as SetupEquipment. It exposes the metadata (name, note), the thermal scalars (energy efficiency, working-temperature ceiling), the gear-shift spindle speed, the two dry-run coefficients, and the power / torque contour lists. Key Model: SpindleCapability Assistant Model: SetupEquipment — owns the capability as SpindleCapability and its optional side-file reference SpindleCapabilityFile. MachiningProject — carries that face across the .hincproj save. Layout The branch is one root plus five children, six selectable nodes in all. Each node's editor occupies the dock's PRIMARY row, and all six — the root included — register the same CONTENT-column view, the two contour charts, so the charts stay mounted while the operator walks the branch. Control Tree Branch Spindle Capability Root Panel — equipment/spindle, item type SpindleCapabilityRoot Object Management Menu Button — Load / Save As / Copy / Paste / XML over file extension .SpindleCapability, load type Hi.Milling.SpindleCapability, HiMech, rel file SpindleCapability.xml, based at the project directory. This is the whole file surface of the editor. Caption — the capability's name, or a “no capability” note. Empty state, while nothing is attached: an hourglass, a “not attached to project” line and a hint pointing at the ⋮ menu's Load entry. Name TextField — Name. Note TextField — Note. equipment/spindle/thermal — “Thermal / Energy”, item type SpindleScalars Energy Efficiency NumberField — EnergyEfficiency, clamped to 0 – 1. Working Temperature Upper Boundary NumberField (°C) — WorkingTemperatureUpperBoundary_C. equipment/spindle/gear-shift — “Gear Shift”, item type SpindleScalars Has-Gear-Shift CheckBox — flips GearShiftSpindleSpeed_rpm between null (no mechanism) and 0 (mechanism present; the operator dials in the speed). Gear Shift Spindle Speed NumberField (rpm) — always rendered, disabled until the checkbox is on. equipment/spindle/dry-run — “Dry-Run Coefficients”, item type SpindleScalars Friction Power Coefficient NumberField (mW/rpm) — DryRunFrictionPowerCoefficient_mWdrpm. Windage Power Coefficient NumberField (pW/rpm³) — DryRunWindagePowerCoefficient_pWdrpm3. equipment/spindle/power — “Power Contours”, item type SpindleContour Count line and an Add button. Contour Selector — a select over the contour list, each entry labelled by its workable duration (n min, or Continuous for the infinite one). Edit-duration Button — opens the modal below. Delete Button — confirms, then removes the selected contour. Disabled at one remaining contour. Points Table — the selected contour's points, one row per point: a spindle-speed cell (rpm, min: 0), a value cell, an insert-next button that clones the row, and a double-click remove that is disabled at one remaining point. A cell edit replaces the whole point list server-side. Empty state, when the axis has no contour yet. Edit-duration Modal Continuous (∞) CheckBox — disabled when another contour already holds the continuous key. Workable Duration NumberField (min), shown while Continuous is off, min: 0. Save rejects a non-positive duration and is a no-op when the key is unchanged. equipment/spindle/torque — “Torque Contours”, item type SpindleContour, the same shape over the torque list. Shared content view, registered by the root and by all five children: the two contour charts in the General Setup page's CONTENT column. Power chart and Torque chart, each with a chip legend — one chip per contour, showing its duration and, on hover, its point count. Clicking a chip selects the contour the PRIMARY-row editor edits. A vertical marker line at the gear-shift spindle speed, while one is set. Its own not-attached empty state, mirroring the root panel's. Behavior Rpm ↔ cycles/s conversion lives server-side. SpindleCapability stores spindle speed in cycles/s (Hz); the controller converts to rpm in its DTOs and back on write. The frontend only ever sees rpm. Nullable gear shift. The Has-Gear-Shift checkbox writes 0 when checked and null when cleared, which is how the model distinguishes “mechanism present, speed not yet dialled in” from “no gear-shift mechanism”. One state, thin views throughout. Every panel on the branch — root, the three scalar sections, the two contour sections and the charts — reads and writes one module-singleton composable. A point edit therefore redraws the chart in the same tick, and a legend click moves the editor. The composable installs a single project-change watch that reloads on open and clears on close. No cache chain. These scalars feed the cutting-force and thermal physics, not the setup canvas, so the branch's afterChange does nothing — unlike the geometry branches, nothing here clears a geometry cache. Add Contour. The prompt is pre-filled with 60; a blank entry means continuous (∞). A duration already present is refused, a second continuous contour included. The new contour is seeded from the currently selected contour, falling back to the first in the list, and to a built-in default curve when the axis is empty — so the operator rarely draws from scratch. Project-scoped, and forwarded to the run. The capability lives on the authored equipment face and is persisted with the .hincproj save; setting SpindleCapabilityFile externalizes it to a side-file instead. The runtime equipment face holds the same object by reference, so a scalar or point edit is visible to a run immediately; a replacement (Load, Paste, XML Apply) re-stamps that reference through the project service's ForwardSetupEnvironmentToExecution. Load / Paste / XML-Apply only swap the IndexService entry. The root panel then installs the result onto the equipment through the controller's update, and reloads the snapshot and the key. The controller's initialize indexes a blank placeholder when nothing is attached yet, which is what keeps the ⋮ menu usable — and Load reachable — on a project with no capability. Source Code Path See HiNC App Anatomy for git repository links. Web Application HiNC-2025-webservice (Quasar CLI SPA): wwwroot-src/src/components/controlTree/useControlTreeHost.ts — builds the equipment/spindle root (item type SpindleCapabilityRoot) and its five children: thermal, gear-shift and dry-run as SpindleScalars, power and torque as SpindleContour. wwwroot-src/src/components/controlTree/itemTypes.ts — registers those three item types and gives all of them the same CONTENT-column view. wwwroot-src/src/components/controlTree/SpindleCapabilityPanel.vue — the branch root panel: the Object Management button, the name caption, the not-attached empty state, and the Name / Note fields. wwwroot-src/src/components/controlTree/SpindleScalarsPanel.vue — one scalar section per role path: thermal, gear-shift (checkbox plus the rpm field, disabled while the value is null) and dry-run. wwwroot-src/src/components/controlTree/SpindleContourPanel.vue — the power / torque child: the count line, Add, the contour selector, the edit-duration modal and the delete button, hosting the point editor. wwwroot-src/src/components/spindle/SpindleContourEditor.vue — the selected contour's numeric points table; its own header is hidden when the tree panel drives it. wwwroot-src/src/components/spindle/SpindleContoursPanel.vue — the CONTENT-column view every spindle item registers: both charts. wwwroot-src/src/components/spindle/SpindleContoursChart.vue — one plotted chart with the clickable chip legend that selects the contour the editor edits, plus the gear-shift marker line. wwwroot-src/src/components/controlTree/ContentSlavePanel.vue — the General Setup page's CONTENT column, which mounts whichever content panel the selection's item type registers; it deliberately leaves that component unkeyed so the charts survive a move between the branch's six nodes. wwwroot-src/src/composables/useSpindleCapability.ts — the module-singleton state and every mutation on the branch: the scalar handlers, add / remove / rename contour, the point updates and the object-management install hooks. wwwroot-src/src/components/widgets/ObjectManagementMenuButton.vue — the reused ⋮ menu carrying Load / Save As / Copy / Paste / XML for the .SpindleCapability file surface. wwwroot-src/src/api/spindleCapability.ts — typed client for /api/mech/spindle-capability/*. wwwroot-src/src/router/routes.ts — the spindle-capability/:tab? redirect (the tab mapped onto the branch child id) and the equipment/spindle redirect, both landing on general-setup?tree=…. wwwroot-src/src/router/treeRoutes.ts — defines the tab segments that redirect accepts: thermal, gear-shift, dry-run, power, torque. Mech/SpindleCapabilityController.cs — REST surface at /api/mech/spindle-capability over the authored equipment face's capability: GET / — flat snapshot: metadata plus the contour keys of each axis. GET /power-contours, GET /torque-contours — per-axis contour lists with their points. PUT /name | /note | /energy-efficiency | /working-temperature-upper-boundary-c | /gear-shift-spindle-speed-rpm | /dry-run-friction-power-coefficient-mwdrpm | /dry-run-windage-power-coefficient-pwdrpm3 — one scalar each. POST /power-contours | /torque-contours — add one contour. DELETE /power-contours/{key} | /torque-contours/{key} — remove one contour ({key} accepts numeric strings and \"inf\" / \"infinity\"). PUT /power-contours/{key}/points | /torque-contours/{key}/points — replace one contour's points; this is what backs per-point editing. PUT /power-contours/{key}/key | /torque-contours/{key}/key — rename a contour's workable-duration key, refusing a key that already exists; this is what backs the edit-duration modal. GET /xml — serialise to XML text. POST /load, POST /load-file, POST /reload — install from XML text, from a file under a named root, or from the file already stamped on the equipment. PUT /capability-file — set the side-file reference without reloading. POST /initialize, POST /update — index the capability for the Object Management button, and install the swapped-in object back onto the equipment. HiAPI Engine HiMech/Milling/SpindleCapability.cs — the model: EnergyEfficiency, WorkingTemperatureUpperBoundary_K with its _C accessor, the nullable GearShiftSpindleSpeed_cycleds with its _rpm convenience property, the two dry-run coefficients and the power / torque contour dictionaries keyed by workable duration. HiMech/Machining/MachiningEquipmentUtils/SetupEquipment.cs — the authored equipment face that owns the capability and its file reference and serializes them, inline or as a side-file reference. See Also Mechanism Builder Page — same file-level IO pattern (Load / Reload / Save As) but user-scoped rather than project-scoped. Background / Coolant — sibling branch of the same Control Tree, editing the same authored equipment face. Spindle Capability — what the model represents physically and how the per-step ratios come out of it." + "summary": "Spindle Capability The Spindle Capability editor is the equipment/spindle branch of the General Setup page's Control Tree (/general-setup?tree=equipment/spindle), the equipment child after Machine Tool. Two older paths redirect onto it: /spindle-capability/:tab?, whose tab segment maps straight onto one of the branch's five children, and /equipment/spindle. The menu bar carries no entry of its own for it — the Page menu reaches General Setup, and the tree reaches the branch. It edits SpindleCapability on the project's authored equipment face, SetupEquipment, reached as SetupEquipment. It exposes the metadata (name, note), the thermal scalars (energy efficiency, working-temperature ceiling), the gear-shift spindle speed, the two dry-run coefficients, and the power / torque contour lists. Key Model: SpindleCapability Assistant Model: SetupEquipment — owns the capability as SpindleCapability and its optional side-file reference SpindleCapabilityFile. MachiningProject — carries that face across the .hincproj save. Layout The branch is one root plus five children, six selectable nodes in all. Each node's editor occupies the dock's PRIMARY row, and all six — the root included — register the same CONTENT-column view, the two contour charts, so the charts stay mounted while the operator walks the branch. Control Tree Branch Spindle Capability Root Panel — equipment/spindle, item type SpindleCapabilityRoot Object Management Menu Button — Load / Save As / Copy / Paste / XML over file extension .SpindleCapability, load type Hi.Milling.SpindleCapability, HiMech, rel file SpindleCapability.xml, based at the project directory. This is the whole file surface of the editor. Caption — the capability's name, or a “no capability” note. Empty state, while nothing is attached: an hourglass, a “not attached to project” line and a hint pointing at the ⋮ menu's Load entry. Name TextField — Name. Note TextField — Note. equipment/spindle/thermal — “Thermal / Energy”, item type SpindleScalars Energy Efficiency NumberField — EnergyEfficiency, clamped to 0 – 1. Working Temperature Upper Boundary NumberField (°C) — WorkingTemperatureUpperBoundary_C. equipment/spindle/gear-shift — “Gear Shift”, item type SpindleScalars Has-Gear-Shift CheckBox — flips GearShiftSpindleSpeed_rpm between null (no mechanism) and 0 (mechanism present; the operator dials in the speed). Gear Shift Spindle Speed NumberField (rpm) — always rendered, disabled until the checkbox is on. equipment/spindle/dry-run — “Dry-Run Coefficients”, item type SpindleScalars Friction Power Coefficient NumberField (mW/rpm) — DryRunFrictionPowerCoefficient_mWdrpm. Windage Power Coefficient NumberField (pW/rpm³) — DryRunWindagePowerCoefficient_pWdrpm3. equipment/spindle/power — “Power Contours”, item type SpindleContour Count line and an Add button. Contour Selector — a select over the contour list, each entry labelled by its workable duration (n min, or Continuous for the infinite one). Edit-duration Button — opens the modal below. Delete Button — confirms, then removes the selected contour. Disabled at one remaining contour. Points Table — the selected contour's points, one row per point: a spindle-speed cell (rpm, min: 0), a value cell, an insert-next button that clones the row, and a double-click remove that is disabled at one remaining point. A cell edit replaces the whole point list server-side. Empty state, when the axis has no contour yet. Edit-duration Modal Continuous (∞) CheckBox — disabled when another contour already holds the continuous key. Workable Duration NumberField (min), shown while Continuous is off, min: 0. Save rejects a non-positive duration and is a no-op when the key is unchanged. equipment/spindle/torque — “Torque Contours”, item type SpindleContour, the same shape over the torque list. Shared content view, registered by the root and by all five children: the two contour charts in the General Setup page's CONTENT column. Power chart and Torque chart, each with a chip legend — one chip per contour, showing its duration and, on hover, its point count. Clicking a chip selects the contour the PRIMARY-row editor edits. A vertical marker line at the gear-shift spindle speed, while one is set. Its own not-attached empty state, mirroring the root panel's. Behavior Rpm ↔ cycles/s conversion lives server-side. SpindleCapability stores spindle speed in cycles/s (Hz); the controller converts to rpm in its DTOs and back on write. The frontend only ever sees rpm. Nullable gear shift. The Has-Gear-Shift checkbox writes 0 when checked and null when cleared, which is how the model distinguishes “mechanism present, speed not yet dialled in” from “no gear-shift mechanism”. One state, thin views throughout. Every panel on the branch — root, the three scalar sections, the two contour sections and the charts — reads and writes one module-singleton composable. A point edit therefore redraws the chart in the same tick, and a legend click moves the editor. The composable installs a single project-change watch that reloads on open and clears on close. No cache chain. These scalars feed the cutting-force and thermal physics, not the setup canvas, so the branch's afterChange does nothing — unlike the geometry branches, nothing here clears a geometry cache. Add Contour. The prompt is pre-filled with 60; a blank entry means continuous (∞). A duration already present is refused, a second continuous contour included. The new contour is seeded from the currently selected contour, falling back to the first in the list, and to a built-in default curve when the axis is empty — so the operator rarely draws from scratch. Project-scoped, and forwarded to the run. The capability lives on the authored equipment face and is persisted with the .hincproj save; setting SpindleCapabilityFile externalizes it to a side-file instead. The runtime equipment face holds the same object by reference, so a scalar or point edit is visible to a run immediately; a replacement (Load, Paste, XML Apply) re-stamps that reference through the project service's ForwardSetupEnvironmentToExecution. Load / Paste / XML-Apply only swap the IndexService entry. The root panel then installs the result onto the equipment through the controller's update, and reloads the snapshot and the key. The controller's initialize indexes a blank placeholder when nothing is attached yet, which is what keeps the ⋮ menu usable — and Load reachable — on a project with no capability. Source Code Path See HiNC App Anatomy for git repository links. Web Application HiNC-2025-webservice (Quasar CLI SPA): wwwroot-src/src/components/controlTree/useControlTreeHost.ts — builds the equipment/spindle root (item type SpindleCapabilityRoot) and its five children: thermal, gear-shift and dry-run as SpindleScalars, power and torque as SpindleContour. wwwroot-src/src/components/controlTree/itemTypes.ts — registers those three item types and gives all of them the same CONTENT-column view. wwwroot-src/src/components/controlTree/SpindleCapabilityPanel.vue — the branch root panel: the Object Management button, the name caption, the not-attached empty state, and the Name / Note fields. wwwroot-src/src/components/controlTree/SpindleScalarsPanel.vue — one scalar section per role path: thermal, gear-shift (checkbox plus the rpm field, disabled while the value is null) and dry-run. wwwroot-src/src/components/controlTree/SpindleContourPanel.vue — the power / torque child: the count line, Add, the contour selector, the edit-duration modal and the delete button, hosting the point editor. wwwroot-src/src/components/spindle/SpindleContourEditor.vue — the selected contour's numeric points table; its own header is hidden when the tree panel drives it. wwwroot-src/src/components/spindle/SpindleContoursPanel.vue — the CONTENT-column view every spindle item registers: both charts. wwwroot-src/src/components/spindle/SpindleContoursChart.vue — one plotted chart with the clickable chip legend that selects the contour the editor edits, plus the gear-shift marker line. wwwroot-src/src/components/controlTree/ContentSlavePanel.vue — the General Setup page's CONTENT column, which mounts whichever content panel the selection's item type registers; it deliberately leaves that component unkeyed so the charts survive a move between the branch's six nodes. wwwroot-src/src/composables/useSpindleCapability.ts — the module-singleton state and every mutation on the branch: the scalar handlers, add / remove / rename contour, the point updates and the object-management install hooks. wwwroot-src/src/components/widgets/ObjectManagementMenuButton.vue — the reused ⋮ menu carrying Load / Save As / Copy / Paste / XML for the .SpindleCapability file surface. wwwroot-src/src/api/spindleCapability.ts — typed client for /api/mech/spindle-capability/*. wwwroot-src/src/router/routes.ts — the spindle-capability/:tab? redirect (the tab mapped onto the branch child id) and the equipment/spindle redirect, both landing on general-setup?tree=…. wwwroot-src/src/router/treeRoutes.ts — defines the tab segments that redirect accepts: thermal, gear-shift, dry-run, power, torque. Mech/SpindleCapabilityController.cs — REST surface at /api/mech/spindle-capability over the authored equipment face's capability: GET / — flat snapshot: metadata plus the contour keys of each axis. GET /power-contours, GET /torque-contours — per-axis contour lists with their points. PUT /name | /note | /energy-efficiency | /working-temperature-upper-boundary-c | /gear-shift-spindle-speed-rpm | /dry-run-friction-power-coefficient-mwdrpm | /dry-run-windage-power-coefficient-pwdrpm3 — one scalar each. POST /power-contours | /torque-contours — add one contour. DELETE /power-contours/{key} | /torque-contours/{key} — remove one contour ({key} accepts numeric strings and \"inf\" / \"infinity\"). PUT /power-contours/{key}/points | /torque-contours/{key}/points — replace one contour's points; this is what backs per-point editing. PUT /power-contours/{key}/key | /torque-contours/{key}/key — rename a contour's workable-duration key, refusing a key that already exists; this is what backs the edit-duration modal. GET /xml — serialise to XML text. POST /load, POST /load-file, POST /reload — install from XML text, from a file under a named root, or from the file already stamped on the equipment. PUT /capability-file — set the side-file reference without reloading. POST /initialize, POST /update — index the capability for the Object Management button, and install the swapped-in object back onto the equipment. HiAPI Engine HiMech/Milling/SpindleCapability.cs — the model: EnergyEfficiency, WorkingTemperatureUpperBoundary_K with its _C accessor, the nullable GearShiftSpindleSpeed_cycleds with its _rpm convenience property, the two dry-run coefficients and the power / torque contour dictionaries keyed by workable duration. HiMech/Machining/MachiningEquipmentUtils/SetupEquipment.cs — the authored equipment face that owns the capability and its file reference and serializes them, inline or as a side-file reference. See Also Mechanism Builder Page — same file-level IO pattern (Load / Reload / Save As) but user-scoped rather than project-scoped. Environment: Ambient Temperature / Coolant — sibling root of the same Control Tree, editing the same authored equipment face. Spindle Capability — what the model represents physically and how the per-step ratios come out of it." }, "anatomy/general-setup/workpiece.html": { "href": "anatomy/general-setup/workpiece.html", @@ -322,12 +322,12 @@ "anatomy/legacy-controller-settings.html": { "href": "anatomy/legacy-controller-settings.html", "title": "Legacy Controller Model (HardNcEnv) | HiAPI-C# 2025", - "summary": "Legacy Controller Model (HardNcEnv) HardNcEnv is the HardNc controller model: the one the project still carries as MachiningProject.NcEnv and serializes as its NcEnv element, and the one the deprecating HardNc pipeline plays. It is a model with no screen. The Legacy-Controller page at /controller/:tab? that edited it was removed on 2026-09-11 — /controller/… now redirects to /general-setup?tree=equipment/controller, following the route file's convention for retired pages — and controller settings are edited on the General Setup page's Controller Branch, the settings face of the SoftNc runner, which is the live pipeline. What survives of the legacy face is its REST implementation, Controller/ControllerController.cs, still mounted under /api/Controller/*, and its typed client wwwroot-src/src/api/controller.ts, kept as those endpoints' only client; one wrapper in it, getCncBrand, is still called from a live component. This page is what the model holds: how it stands to the runner, what the live pipeline still reads from it, the settings that retire with it, the ones the branch edits a runner-side copy of, and the one marker class both stores draw a work coordinate with. The Model, and the Runner Beside It The project carries both models side by side and serializes both. HardNcEnv is loaded from the project's own NcEnv element unconditionally; NcRunnerSuit — the runner plus the project's per-case dependency list — is read from its own nested element. The legacy element is a fallback source for the suit rather than a shared store: a project file that carries no runner element derives one from the legacy element at load time, and from then on the two drift apart, because every later edit lands on one of them alone. The legacy model is still read at play time. The legacy NC runner is constructed over a delegate onto the project's NcEnv, so a replacement installed through the update endpoint — the removed page's object-management chain was its caller, and nothing in the SPA calls it now — propagates without rewiring, and a project-level switch selects which of the two pipelines plays. That switch defaults to the SoftNc pipeline and no screen in the web application changes it; it is a scripting property, EnableSoftNcRunner(API). The legacy NC optimisation route is the other live reader: it is taken whenever the switch is off or the session holds no played SoftNc layers, and it is handed MachiningProject.NcEnv directly. What the Live Pipeline Still Reads From It Selecting the SoftNc pipeline does not silence the legacy model. Four reads still land on it with the switch on, so a value that only the legacy endpoints or the project XML can change still shows up on a runner play. Stroke limits, as a fallback. The per-step stroke check reads the runner's IStrokeLimitConfig when the switch is on and one is present, and falls back to the legacy stroke boxes otherwise — a CSV or NX-CL suit carries no stroke config, so a play on those falls through to the boxes. The pre-play audit that warns of an unlimited linear axis reads both sources end by end, the runner's first and the legacy box behind it, and stays silent for an axis either source guards. The home position, as a fallback. The chain is re-homed from the runner's home config; the legacy HomeMc fills in only when no linear axis was ever configured there. The Execution canvas's coordinate markers. The IsoCoordinate and HeidenhainCoordinate rendering flags on the Execution page draw from the legacy tables — see Two Faces of a Work Coordinate. The Execution tool bar's brand. The Scene dropdown offers its Heidenhain-coordinate entry only while the brand is Heidenhain, and the brand it asks for is the legacy model's, through getCncBrand — the one wrapper in wwwroot-src/src/api/controller.ts a live component still calls. The kinematics solver the service builds is mirrored onto NcEnv.XyzabcSolver as well, but that slot is wiring the service maintains rather than a setting, and it is never serialized. Settings That Retire With the Model Four controls had no editor anywhere in the web application but the removed screen. None of them gained one on the branch: three are legacy-only settings and retire with the model, and the fourth is an action the runner path does not offer. Every one keeps its endpoint under /api/Controller/*, so the value can still be read and written over REST or in the project XML — there is just no UI for it. Align P0 — not offered on the runner path The removed Coordinate Table tab carried a third row action beside P0 and M0: Align P0, which moves the part so that program zero lands on the offset the row holds — the reproducing direction, program zero onto the work offset in the manual's terms. It did not write the coordinate; it wrote the fixture's geometry-to-table transformer, so the workpiece and fixture moved together and the runtime face followed at the next rebuild. The branch's Work Coordinates leaf carries P0 and M0 only, which write the row from the machine position — the opposite direction — and no alignment. The operation is not offered on the runner path. The tab's undo history — Undo Align and Redo Align over two component-local stacks, the undo stack capped at 32 entries — was the component's own and went with it; the endpoint never kept an undo slot. It still answers with the assigned translation plus the transformer as it stood before and after the write, both serialized as XML, and the stateless revert endpoint still parses such a snapshot and assigns it as the fixture's transformer; nothing in the SPA posts to either now. The engine exposes the same operation as a script call, AlignWorkpieceProgramZeroToIso(API), which looks the row up in the legacy model's ISO coordinate table — an API for a script, not a replacement for the removed control. Enable Shortest Rotary Path EnableShortestRotary constructs true, and its only editor was the removed Config tab's single toggle. On the legacy pipeline the flag gates one step: each rotary axis of a block is cycled into the ±180° window around the previous block's value. The flag is narrower than its name, because that same cycle is applied unconditionally on Heidenhain — the brand branch runs it before the flag is consulted, so clearing it changes nothing there. The runner's dependency layer declares no counterpart: no brand parameter table, no generic config and no branch leaf carries a shortest-rotary switch. What the runner pipeline has instead is the Heidenhain M126 / M127 pair, modal codes read from the program text rather than from any setting. Max rotary speed per axis MaxRotarySpeedABC_radds is the per-axis rotary speed ceiling the HardNc pipeline clamps feed and cycle time against; its editor was the removed Machine tab's Max Speed (rpm) column. On the runner pipeline the ceiling is not a setting of its own: the polar feed clamp reads it from the per-axis rapid-feedrate bucket, IRapidFeedrateConfig, and the legacy import funnels this field into that bucket at rpm × 360 deg/min, so the branch's Rapid Feedrates leaf edits the runner-side number. The legacy field itself retires with the model. Heidenhain master-axis character HeidenhainMasterAxisChar is a character face over the integer axis direction the PLANE … SEQ solution family is resolved against; its editor was a second card the removed Brand tab grew while the brand was Heidenhain, one select over A, B, C. The setter takes only A, B or C and throws on anything else; the PUT endpoint upper-cases the first character it is sent and answers 400 to anything but those three. On the runner pipeline the master rotary is derived rather than configured — it is the first declared rotary axis — so the branch has nothing to expose and no leaf for it. What the Branch Edits a Runner-Side Copy Of Naming what is not legacy-only matters as much. The CNC brand, the stroke limits, the rapid feed, the tool-change time, the tool offset table with its tool-house dependence, the work coordinates with their P0 and M0 actions, and the Heidenhain datum preset and datum shift tables all have editors on the branch — see Brand Matrix for which of those leaves each brand grows. The branch edits the runner's copy of each; the legacy copy in HardNcEnv is reachable only through its endpoint and the project XML, and the two are not kept in step. One flag sits outside both models. Set ideal offset dependent on tool house is a project-level configuration flag, and the branch's Tool Offsets leaf and the legacy ideal-offset-dependent endpoint read and write that one flag. The two tables stay separate: the legacy set-ideal-offset-from-toolhouse endpoint — the removed Offset Table tab's Refresh from Tool House — recomputes MillingToolOffsetTable from MachiningToolHouse, while the branch's refresh recomputes the runner's own tool-offset table. Two Faces of a Work Coordinate The work-coordinate marker is one displayee class serving two providers. The Execution canvas draws it from IsoCoordinateTable — a IsoCoordinateTable instance owned by the legacy model, which constructs with G54 … G59 and G59.1 … G59.9 all at zero — and draws its Heidenhain datum marker from the legacy datum tables the same way. The General Setup canvas builds the same displayee over the active runner's effective IIsoCoordinateConfig instead, which on most brands is the brand parameter table. Same marker, same code, two stores. Which row the Execution marker draws is the displayee's own id, constructed as G54. Its only writer is the legacy iso-coordinate-selection endpoint, which the removed tab's row selection posted to and nothing in the SPA posts to now, so the Execution marker stays on G54. Whether it is drawn is the IsoCoordinate rendering flag, toggled from the Execution page's Scene dropdown; all three coordinate flags are off in the shipped rendering-flag set — as are the machine tool and the cutter, leaving the workpiece, the fixture, the dimension bar and the cutter-location strip as the four that arrive on. The General Setup marker's row is a user-config value of its own, with an endpoint on the equipment-setup display controller. Source Code Path See HiNC App Anatomy for git repository links. Web Application HiNC-2025-webservice (Quasar CLI SPA): Controller/ControllerController.cs — the model's REST face, still mounted: every legacy table and setting, the align endpoint that snapshots the transformer either side of the write, the stateless revert, the update rebind, and the marker-row selection. wwwroot-src/src/api/controller.ts — the typed wrappers over all of it, kept as those endpoints' only client; getCncBrand and the brand constants are what a live component still imports. wwwroot-src/src/components/execution/ExecutionExtendedToolBar.vue — that component: the Scene dropdown that toggles the coordinate flags, and asks the legacy model for its brand. wwwroot-src/src/api/renderingFlags.ts — the flag indices the Scene dropdown writes. Disp/ExecutionDisplayee.cs — the Execution canvas's displayee: the shipped flag set, and the work-coordinate and datum markers it builds over the legacy tables. Disp/IsoCoordinateEntryDisplayee.cs — the one marker class both canvases draw with. Disp/EquipmentSetupDisplayee.cs — the General Setup canvas's marker, over the runner's providers. wwwroot-src/src/router/routes.ts — the /controller/… redirect stub onto the Controller branch. HiAPI Engine HiUniNc/Numerical/HardNcEnv.cs — the model: the coordinate, datum and offset tables, the stroke boxes that construct infinite, the rapid rate and tooling time, the per-axis rotary speed ceiling, the shortest-rotary flag with its Heidenhain exclusion, and the master-axis character over its integer direction. HiUniNc/Numerical/HardNcLine.cs — the legacy consumers of two of those settings: the shortest-rotary path application and the SEQ solve that reads the master-axis direction. HiUniNc/Numerical/NcProc.cs — the legacy consumer of the rotary speed ceiling: feed and cycle time re-limited per rotary axis. HiUniNc/Numerical/MillingToolOffsetTable.cs — the offset table and the tool-house recompute the legacy refresh endpoint calls. HiMech/NcParsers/Dependencys/Generic/IsoCoordinateTable.cs — the coordinate table type and the fifteen G-code keys it constructs with, shared by name with the runner's brand-agnostic table. HiMech/Machining/MachiningEquipmentUtils/MachiningEquipmentUtil.cs — the alignment itself: the translation written into the fixture's geometry-to-table transformer. HiMech/NcParsers/SoftNcRunner.cs — the legacy import: which legacy fields are funnelled into which runner dependency, including the rotary speed conversion into the rapid-feedrate config. HiMech/NcParsers/LogicSyntaxs/PolarInterpolationUtil.cs — the rotary speed ceiling the runner pipeline reads, and why it is the rapid-rate bucket rather than a setting of its own. HiMech/NcParsers/LogicSyntaxs/Heidenhain/HeidenhainPlaneTiltSyntax.cs — the derived master rotary on the runner pipeline: the first declared rotary axis, with no configured alternative. HiNc/MachiningProcs/MachiningProject.cs — where both models hang off the project, and the load path that derives a runner from the legacy element only when no runner element is present. HiNc/MachiningProcs/LocalProjectService.cs — the legacy runner built over a delegate onto the project's model, the switch that selects which pipeline is active, and the stroke-limit and home-position fallbacks onto the legacy model. HiNc/Numerical/FilePlayers/HardNcRunner.cs — the legacy runner itself. HiNc/MachiningProcs/SessionShell.cs — the scripting face of the pipeline switch and of the alignment, and the optimisation route that passes the legacy model directly. See Also Controller Branch — the SoftNcRunner-native controller branch: the live settings face, and the editor for everything named above as having a runner-side copy General Setup Page — the page that hosts that branch, and the rest of the equipment tree beside it" + "summary": "Legacy Controller Model (HardNcEnv) HardNcEnv is the HardNc controller model: the one the project still carries as MachiningProject.NcEnv and serializes as its NcEnv element, and the one the deprecating HardNc pipeline plays. It is a model with no screen. The Legacy-Controller page at /controller/:tab? that edited it was removed on 2026-09-11 — /controller/… now redirects to /general-setup?tree=equipment/controller, following the route file's convention for retired pages — and controller settings are edited on the General Setup page's Controller Branch, the settings face of the SoftNc runner, which is the live pipeline. What survives of the legacy face is its REST implementation, Controller/ControllerController.cs, still mounted under /api/Controller/*, and its typed client wwwroot-src/src/api/controller.ts, kept as those endpoints' only client; one wrapper in it, getCncBrand, is still called from a live component. This page is what the model holds: how it stands to the runner, what the live pipeline still reads from it, the settings that retire with it, the ones the branch edits a runner-side copy of, and the one marker class both stores draw a work coordinate with. The Model, and the Runner Beside It The project carries both models side by side and serializes both. HardNcEnv is loaded from the project's own NcEnv element unconditionally; NcRunnerSuit — the runner plus the project's per-case dependency list — is read from its own nested element. The legacy element is a fallback source for the suit rather than a shared store: a project file that carries no runner element derives one from the legacy element at load time, and from then on the two drift apart, because every later edit lands on one of them alone. The legacy model is still read at play time. The legacy NC runner is constructed over a delegate onto the project's NcEnv, so a replacement installed through the update endpoint — the removed page's object-management chain was its caller, and nothing in the SPA calls it now — propagates without rewiring, and a project-level switch selects which of the two pipelines plays. That switch defaults to the SoftNc pipeline and no screen in the web application changes it; it is a scripting property, EnableSoftNcRunner(API). The legacy NC optimisation route is the other live reader: it is taken whenever the switch is off or the session holds no played SoftNc layers, and it is handed MachiningProject.NcEnv directly. What the Live Pipeline Still Reads From It Selecting the SoftNc pipeline does not silence the legacy model. Four reads still land on it with the switch on, so a value that only the legacy endpoints or the project XML can change still shows up on a runner play. Stroke limits, as a fallback and as a seed. The per-step stroke check reads the runner's IStrokeLimitConfig when the switch is on and one is present, and falls back to the legacy stroke boxes otherwise — a CSV or NX-CL suit carries no stroke config, so a play on those falls through to the boxes. When a project loads, the boxes' finite ends are also copied into the runner's controller parameter table for every axis that carries no end there (PopulateLegacyStrokeLimitsWhereUnset; an explicit row wins), so a project that declared its travel only in the boxes is checked against it on SoftNc — and its tilt solves prefer the rotary branch inside that travel. The pre-play audit that warns of an unlimited linear axis reads both sources end by end, the runner's first and the legacy box behind it, and stays silent for an axis either source guards. The home position, as a fallback. The chain is re-homed from the runner's home config; the legacy HomeMc fills in only when no linear axis was ever configured there. The Execution canvas's coordinate markers. The IsoCoordinate and HeidenhainCoordinate rendering flags on the Execution page draw from the legacy tables — see Two Faces of a Work Coordinate. The Execution tool bar's brand. The Scene dropdown offers its Heidenhain-coordinate entry only while the brand is Heidenhain, and the brand it asks for is the legacy model's, through getCncBrand — the one wrapper in wwwroot-src/src/api/controller.ts a live component still calls. The kinematics solver the service builds is mirrored onto NcEnv.XyzabcSolver as well, but that slot is wiring the service maintains rather than a setting, and it is never serialized. Settings That Retire With the Model Four controls had no editor anywhere in the web application but the removed screen. None of them gained one on the branch: three are legacy-only settings and retire with the model, and the fourth is an action the runner path does not offer. Every one keeps its endpoint under /api/Controller/*, so the value can still be read and written over REST or in the project XML — there is just no UI for it. Align P0 — not offered on the runner path The removed Coordinate Table tab carried a third row action beside P0 and M0: Align P0, which moves the part so that program zero lands on the offset the row holds — the reproducing direction, program zero onto the work offset in the manual's terms. It did not write the coordinate; it wrote the fixture's geometry-to-table transformer, so the workpiece and fixture moved together and the runtime face followed at the next rebuild. The branch's Work Coordinates leaf carries P0 and M0 only, which write the row from the machine position — the opposite direction — and no alignment. The operation is not offered on the runner path. The tab's undo history — Undo Align and Redo Align over two component-local stacks, the undo stack capped at 32 entries — was the component's own and went with it; the endpoint never kept an undo slot. It still answers with the assigned translation plus the transformer as it stood before and after the write, both serialized as XML, and the stateless revert endpoint still parses such a snapshot and assigns it as the fixture's transformer; nothing in the SPA posts to either now. The engine exposes the same operation as a script call, AlignWorkpieceProgramZeroToIso(API), which looks the row up in the legacy model's ISO coordinate table — an API for a script, not a replacement for the removed control. Enable Shortest Rotary Path EnableShortestRotary constructs true, and its only editor was the removed Config tab's single toggle. On the legacy pipeline the flag gates one step: each rotary axis of a block is cycled into the ±180° window around the previous block's value. The flag is narrower than its name, because that same cycle is applied unconditionally on Heidenhain — the brand branch runs it before the flag is consulted, so clearing it changes nothing there. The runner's dependency layer declares no counterpart: no brand parameter table, no generic config and no branch leaf carries a shortest-rotary switch. What the runner pipeline has instead is the Heidenhain M126 / M127 pair, modal codes read from the program text rather than from any setting. Max rotary speed per axis MaxRotarySpeedABC_radds is the per-axis rotary speed ceiling the HardNc pipeline clamps feed and cycle time against; its editor was the removed Machine tab's Max Speed (rpm) column. On the runner pipeline the ceiling is not a setting of its own: the polar feed clamp reads it from the per-axis rapid-feedrate bucket, IRapidFeedrateConfig, and the legacy import funnels this field into that bucket at rpm × 360 deg/min, so the branch's Rapid Feedrates leaf edits the runner-side number. The legacy field itself retires with the model. Heidenhain master-axis character HeidenhainMasterAxisChar is a character face over the integer axis direction the PLANE … SEQ solution family is resolved against; its editor was a second card the removed Brand tab grew while the brand was Heidenhain, one select over A, B, C. The setter takes only A, B or C and throws on anything else; the PUT endpoint upper-cases the first character it is sent and answers 400 to anything but those three. On the runner pipeline the master rotary is derived rather than configured — it is the first declared rotary axis — so the branch has nothing to expose and no leaf for it. What the Branch Edits a Runner-Side Copy Of Naming what is not legacy-only matters as much. The CNC brand, the stroke limits, the rapid feed, the tool-change time, the tool offset table with its tool-house dependence, the work coordinates with their P0 and M0 actions, and the Heidenhain datum preset and datum shift tables all have editors on the branch — see Brand Matrix for which of those leaves each brand grows. The branch edits the runner's copy of each; the legacy copy in HardNcEnv is reachable only through its endpoint and the project XML, and the two are not kept in step. One flag sits outside both models. Set ideal offset dependent on tool house is a project-level configuration flag, and the branch's Tool Offsets leaf and the legacy ideal-offset-dependent endpoint read and write that one flag. The two tables stay separate: the legacy set-ideal-offset-from-toolhouse endpoint — the removed Offset Table tab's Refresh from Tool House — recomputes MillingToolOffsetTable from MachiningToolHouse, while the branch's refresh recomputes the runner's own tool-offset table. Two Faces of a Work Coordinate The work-coordinate marker is one displayee class serving two providers. The Execution canvas draws it from IsoCoordinateTable — a IsoCoordinateTable instance owned by the legacy model, which constructs with G54 … G59 and G59.1 … G59.9 all at zero — and draws its Heidenhain datum marker from the legacy datum tables the same way. The General Setup canvas builds the same displayee over the active runner's effective IIsoCoordinateConfig instead, which on most brands is the brand parameter table. Same marker, same code, two stores. Which row the Execution marker draws is the displayee's own id, constructed as G54. Its only writer is the legacy iso-coordinate-selection endpoint, which the removed tab's row selection posted to and nothing in the SPA posts to now, so the Execution marker stays on G54. Whether it is drawn is the IsoCoordinate rendering flag, toggled from the Execution page's Scene dropdown; all three coordinate flags are off in the shipped rendering-flag set — as are the machine tool and the cutter, leaving the workpiece, the fixture, the dimension bar and the cutter-location strip as the four that arrive on. The General Setup marker's row is a user-config value of its own, with an endpoint on the equipment-setup display controller. Source Code Path See HiNC App Anatomy for git repository links. Web Application HiNC-2025-webservice (Quasar CLI SPA): Controller/ControllerController.cs — the model's REST face, still mounted: every legacy table and setting, the align endpoint that snapshots the transformer either side of the write, the stateless revert, the update rebind, and the marker-row selection. wwwroot-src/src/api/controller.ts — the typed wrappers over all of it, kept as those endpoints' only client; getCncBrand and the brand constants are what a live component still imports. wwwroot-src/src/components/execution/ExecutionExtendedToolBar.vue — that component: the Scene dropdown that toggles the coordinate flags, and asks the legacy model for its brand. wwwroot-src/src/api/renderingFlags.ts — the flag indices the Scene dropdown writes. Disp/ExecutionDisplayee.cs — the Execution canvas's displayee: the shipped flag set, and the work-coordinate and datum markers it builds over the legacy tables. Disp/IsoCoordinateEntryDisplayee.cs — the one marker class both canvases draw with. Disp/EquipmentSetupDisplayee.cs — the General Setup canvas's marker, over the runner's providers. wwwroot-src/src/router/routes.ts — the /controller/… redirect stub onto the Controller branch. HiAPI Engine HiUniNc/Numerical/HardNcEnv.cs — the model: the coordinate, datum and offset tables, the stroke boxes that construct infinite, the rapid rate and tooling time, the per-axis rotary speed ceiling, the shortest-rotary flag with its Heidenhain exclusion, and the master-axis character over its integer direction. HiUniNc/Numerical/HardNcLine.cs — the legacy consumers of two of those settings: the shortest-rotary path application and the SEQ solve that reads the master-axis direction. HiUniNc/Numerical/NcProc.cs — the legacy consumer of the rotary speed ceiling: feed and cycle time re-limited per rotary axis. HiUniNc/Numerical/MillingToolOffsetTable.cs — the offset table and the tool-house recompute the legacy refresh endpoint calls. HiMech/NcParsers/Dependencys/Generic/IsoCoordinateTable.cs — the coordinate table type and the fifteen G-code keys it constructs with, shared by name with the runner's brand-agnostic table. HiMech/Machining/MachiningEquipmentUtils/MachiningEquipmentUtil.cs — the alignment itself: the translation written into the fixture's geometry-to-table transformer. HiMech/NcParsers/SoftNcRunner.cs — the legacy import: which legacy fields are funnelled into which runner dependency, including the rotary speed conversion into the rapid-feedrate config. HiMech/NcParsers/LogicSyntaxs/PolarInterpolationUtil.cs — the rotary speed ceiling the runner pipeline reads, and why it is the rapid-rate bucket rather than a setting of its own. HiMech/NcParsers/LogicSyntaxs/Heidenhain/HeidenhainPlaneTiltSyntax.cs — the derived master rotary on the runner pipeline: the first declared rotary axis, with no configured alternative. HiNc/MachiningProcs/MachiningProject.cs — where both models hang off the project, and the load path that derives a runner from the legacy element only when no runner element is present. HiNc/MachiningProcs/LocalProjectService.cs — the legacy runner built over a delegate onto the project's model, the switch that selects which pipeline is active, and the stroke-limit and home-position fallbacks onto the legacy model. HiNc/Numerical/FilePlayers/HardNcRunner.cs — the legacy runner itself. HiNc/MachiningProcs/SessionShell.cs — the scripting face of the pipeline switch and of the alignment, and the optimisation route that passes the legacy model directly. See Also Controller Branch — the SoftNcRunner-native controller branch: the live settings face, and the editor for everything named above as having a runner-side copy General Setup Page — the page that hosts that branch, and the rest of the equipment tree beside it" }, "anatomy/platform/control-tree.html": { "href": "anatomy/platform/control-tree.html", "title": "Control Tree | HiAPI-C# 2025", - "summary": "Control Tree The Control Tree is the engine shared by the two tree-shaped pages of the web client: the Execution page at /execution and the General Setup page at /general-setup. Each page creates exactly one host — useControlTreeHost('execution') or useControlTreeHost('equipment') — provides it to its panes under one injection key, and the host owns everything after that: the node graph, the branch builders, the selection and the ?tree= query that carries it, the editor panel a selection resolves to, the mission enable ticks, and every structural operation on the Mission branch. The Tool House page at /tool-house reuses the same node shape and the same item-type registry but renders a branch as nested tabs and creates no host. Important Node ids are role paths, not identities that survive a version change. Anatomy makes no claim that a ?tree= id is stable across releases; see Tree Ids and Routes for the migration hop that keeps an older link resolving. The Node Every branch of every tree is built from one structure, ControlNode, declared in itemTypes.ts: id — the node's role path, slash-separated, whose first segment is the owning page's scope (execution/…, equipment/…, toolhouse/…). This is the addressing surface: the ?tree= query, the persisted expansion list and the persisted last selection all hold ids. The General Setup page's root carries its scope as its own id, equipment; the Execution page has no node with the bare execution id — its two roots are execution/mission and execution/program, and the segment is a scope key only. label, labelKey, labelParams — the display text; see Display Labels. itemType — the registry key that decides the node's editor and its child builder. key — the bound object. In the geometry and equipment branches it is an IndexService key, re-minted on every re-index; in the Mission branch it is the Mission API command path (0, 1, the dotted 0.2 of a nested list entry); in the Tool House branch it is the tool id as a string. Waves whose panels read a module-level state singleton rather than an indexed object leave it empty — the SoftNc controller leaves, the spindle sections, the Background and Coolant leaves and the Program branch all do. ctx — the parent-provided SlotCtx: the afterChange commit chain, a slot's onCreate create-and-rebind hook, and a slot picker's allowedKinds / allowNone constraints. children — grown by the builders, not declared by the tree column. selectable, info / infoKey, and the mission / program bookkeeping records the Mission and Program waves stamp on their own nodes. The split between id and key is the load-bearing one. A key is re-minted every time the host re-indexes the model, so nothing durable may hang off it; an id names a role in the model and therefore survives a rebuild, which is why expansion state, the URL and the landing selection are all keyed on ids. Two id families are positional rather than role-based: Mission entries are ${parentId}/${index} and Program files are ${parentId}/${index}, so moving or deleting a mission command renumbers its siblings and a link to one names a position in the list rather than that command. The host keeps three id sets of its own that must follow the rows rather than the numbers — the persisted expansion list, the Add Command focus and the selection — and translates all three through every mission row operation it runs; see the row operations. The Item-Type Registry ITEM_TYPES maps an itemType string onto a TreeItemDef carrying up to three members: panel — the editor mounted in the dock's editor row for a node of this type. contentPanel — a large view for the General Setup page's content column. buildChildren — an async builder that returns this node's children. Two flavours of type share the map. Slot types (Geometry, Transformer) have a kind picker as their panel and grow at most one child, the concrete kind, at the kind-independent id ${slot.id}/type — so switching a slot's kind keeps both the selection and the expansion. A slot holding nothing grows no child at all, which for the four geometry slots whose picker offers None is an ordinary state rather than a failure. Kind types (Box3d, StaticTranslation, …) register SoleEditorPanel, which looks the concrete editor up in the geometry and transformer editor maps and binds it to the node's key. The two composite geometry kinds do not embed nested editors: TransformationGeom grows an inner-geometry and an inner-transformer slot, and GeomCombination grows one slot per item, so the tree owns the structure and every panel stays shallow. The map is one flat namespace assembled in itemTypes.ts: the Group stem type and the geometry, transformer, workpiece-leaf, thermal-condition and spindle entries are written inline, and five per-wave registries are spread in beside them. The Execution page's two roots are registry types — MissionRoot and ProgramRoot, from their waves — and no wrapper type stands over them. The three roots the panel host renders itself — Machine Tool, Fixture and Workpiece — have no entry here at all. Wave File What it contributes Mission missionItemTypes.ts MissionRoot, whose panel is informational — the command count and the run-order hint that names the row affordances; MissionCommand, whose panel is the kind's editor, or only a Title field for a List; MissionSection; section children at ${command.id}/${sectionId}; the per-kind bespoke editors, with a generic field editor as the fallback Program programItemTypes.ts ProgramRoot, ProgramFile, ProgramConversionFile; writeback conversions at ${root.id}/dst-${index} Tool House toolHouseItemTypes.ts the tool collection and the per-tool editor branches under toolhouse/tool- /… SoftNc controller softNcItemTypes.ts the controller root and its leaves on two planes — …/machine/ and …/program-data/ — a core every runner grows plus the brand-driven ones Runner suits runnerSuitItemTypes.ts CsvRunnerRoot and ClRunnerRoot, flat single-panel leaves with no builder The Program branch is fetched whole: its root builder takes one file-tree response plus one conversions response and stashes each file's raw subtree on the node, so the file nodes' builder only maps what is already in hand. The SoftNc branch is the opposite — its builder reads the runner snapshot once, and with no runner installed grows nothing at all. Where one resolves, the two plane stems appear over a fixed core that stands for every brand: six machine leaves, and Work Coordinates and Tool Offsets on the program-data plane. The leaves beside that core are the brand-driven ones — each appears only where the snapshot reports its backing table, so a brand switch changes which nodes exist. One flag does double duty: the Siemens $TC_DP flag adds its own two leaves and renames the core Tool Offsets leaf to its ISO G43 H reading, so the two offset ledgers do not read as one. The two runner-suit nodes are conditional, and the host — not the registry — decides. With a project open, a CSV or CL controller node is built when its Preference checkbox is on, or when the current ?tree= value starts with that node's id. The checkbox is device-local and off by default; the route is the only other reveal, deliberately not the persisted last selection, so a node switched off while it is selected does not resurrect itself. Stepping off comes first: when the selection sits on a node the user has just unchecked, the host re-points the URL at the page root before rebuilding. Building a Branch buildSubtree(node, services, depth) is the whole builder. It looks the node's type up, returns without touching children when the type declares no buildChildren or when depth has reached MAX_DEPTH (12, a guard against a self-referencing model), and otherwise awaits the builder, recurses into each returned child, and assigns the result. Building is eager: a branch is materialised in full at build time rather than lazily on expansion. Builders receive one service, registerKey, which registers a freshly minted IndexService key with the page's cleanup hub — see Webapi with Hub-Cleanup Assistance. rebuildBranch(node) is buildSubtree plus one thing: it adds the node's id to the expansion list so the fresh children are visible, and reports a failure as a toast named after the node's display label. The structure-changed event A panel that has changed the shape of the model emits structure-changed (or type-changed, wired to the same handler). The optional payload is a StructureChangeRequest: scopeId — the branch to rebuild. Without it the scope is the selected node itself, which is correct only while the change stays inside the emitting panel's own branch. selectId — the selection to adopt afterwards. It is assigned directly, bypassing the dirty-switch gate, because the emitting panel is being replaced on purpose. A null clears the selection. inserted — entries a panel inserted into a mission list itself: the list node's id, the child index the run starts at and its count. The host then treats the rebuild as a mission operation — it holds the busy gate and slides its index-based ids past the new siblings — rather than as a plain branch refresh. One command editor emits the event: the Program File editor, whose multi-pick turns every extra file into a new Program File command inserted right after it, in pick order; the command panel hosting it re-scopes the event to the parent list, keeps that command selected and passes the insert range along. Two panels emit it with no payload and so take the default scope, their own node: the Program root panel's refresh button, which re-reads the file tree from the current session and rebuilds the Program branch through rebuildBranch, so the branch opens under it; and the GeomCombination item panel after an item add, an item remove or a clear, since its item slots must be regrown. The controller brand switch and the runner's Object-Management install re-scope to the controller root. The Tool House type selectors and a flute add re-scope to their own node; everything that rewrites the tool collection — a new tool, a duplicate, a delete, an id rename, an Object-Management install — re-scopes to the tool-house root, and a flute delete re-scopes to its fluting parent. Every other structural change to the Mission branch is an operation of the host itself, not an event, because the tree rows are the only surface that offers it: Add Command, a drag between rows, Move up / Move down, Duplicate and Delete. A drag is HTML5 drag-and-drop between mission rows; every command row drags, the Mission root row only receives, and where the pointer sits in the target row decides the operation. A plain command row has no edge band: it splits at its midline, the upper half putting the dragged command before that row and the lower half after it — a reorder when both share a list, a relocation across lists otherwise. A List row keeps that before / after reading only in its top and bottom quarters; its middle half, and the whole of the Mission root row, take the command into that list, at the tail. A drop onto the dragged row's own subtree is refused, and a drop aborts when a rebuild mid-drag re-stamped the dragged node, since its id may then name another command. All five run through one helper that holds a busy gate (one operation at a time), runs the open panel's dirty-switch gate, calls the Mission API, translates the expansion list and the Add Command focus through the operation, rebuilds the branch of the list or lists it rewrote — the one list, or the nearest list above both ends of a cross-list drag — and only then translates the selection and names any post-operation selection, since the ids it names exist only after the rebuild. A refused gate drops the operation and says so in a notification (\"Cancelled — the open editor keeps its unsaved edits.\"); the delete's own confirm dialog runs before the gate, so a cancelled delete forces no save prompt on the open editor. The selection moves only when it rides on the acted-on row — that row itself, or a section or nested entry under it. Then it follows a stepped or dragged command, lands on the clone after a duplicate, and after a delete lands on the nearest remaining entry of that list, or on the list node itself once the list is empty. Otherwise the editor the user is in stays on its own, re-indexed row. Add Command never moves the selection: it reveals the new row and makes it the focus, so a run of adds lands in order. The focus is the command most recently selected — a section row counts for its owning command — or the last one added, and an Add Command from a list row's + inserts right after that focus when the focus is a direct entry of that list, and at the list's tail otherwise; the Mission root row's + therefore never chases a focus inside a nested list. Whole-tree rebuilds, and the refreshes that are not rebuilds rebuildTree() replaces the root array outright, and runs after an Object-Management swap of the machine tool or the fixture, after a blank machining chain is created, and after either runner-suit preference flips. On the execution host, an execution-status transition re-runs buildSubtree on the Program root directly rather than through rebuildBranch, so a run does not force that branch open on every transition. Two refreshes deliberately mutate existing nodes instead of rebuilding: A mission command's title is re-read from the entry list and written onto the node's label. A file-backed geometry leaf's label is re-read when its source file changes. The mission one exists because a rebuild of the Mission branch re-mints the per-build stamp that forms part of the editor's remount key, and remounting an open editor mid-edit would cost the user their cursor and any staged autosave. The geometry one is the same principle without the stamp: a title change and a source-file change alter no structure, so the label is all that has to move, and replacing the node under an open file editor would buy nothing. The commit chain The tree has no component bubbling, so the full post-edit commit chain lives on each node as ctx.afterChange, composed level by level as the branch is built. A GeomCombination item's chain cleans that combination's aggregated cache before running its parent's chain; the fixture's chain ends in a geometry-cache clear; the two workpiece geometry slots re-commit the swap-in before clearing their own cache, and skip that re-commit when the slot has been set to none; the fixture's two anchor transformers re-commit and then clear the geometry cache, while the workpiece's two re-commit and clear nothing, since a placement change invalidates no cached solid. Tool-house nodes all share one refresh. Every other family carries a no-op: the Mission, Program, spindle, SoftNc and thermal-condition nodes and the workpiece's Mesh and Material leaves have panels that write straight to the model, and the pages' canvases draw that model; the group stems and the Machine Tool and Workpiece roots have no field editor to commit for at all. Selection and the Dirty-Switch Gate Every selection change funnels through requestSelect(id). It returns immediately when the id is already selected; it refuses outright while a mission row operation, or a tick's own writes, are in flight — the operation ends by naming the post-operation selection, which would silently undo a change landed during its rebuild; otherwise it awaits the mounted panel's optional tryConsumeBeforeSwitch() and abandons the switch when that returns false. Three entrances use it: a click in the tree, a change to the URL's ?tree= value, and a select-node event from the mounted panel — the wire the panel host puts on every registry panel, so a group stem's child list and the Program branch's conversion jumps both arrive through that one. Two paths assign the selection directly and skip the gate: the selectId of a structure change, and the post-operation selection of a mission row operation, which has already run the gate itself. There is no “nothing selected” state. Re-clicking the selected row makes the tree yield null, and that is ignored; an empty ?tree= lands on the persisted last selection for that page when the built tree still contains it, and otherwise on the page's root — General Setup on the equipment host, and Mission, the first of its two roots, on the execution host. The editor row is therefore always alive, and reclaiming its height is the row's own collapse toggle rather than a deselection. The gate itself is registered by the panel host: the mounted registry panel is handed to the host through a template ref, and the host asks that instance for tryConsumeBeforeSwitch. Panels that write one field per request need no gate and register none. One panel exposes it — MissionCommandSlavePanel: on a list entry it waits for a title save already on the wire, then flushes the debounced title save while the command path is still live, and allows the switch only when that save landed; on any other entry it forwards its inner editor's gate. Two editors have one. The Script editor first lets a save already on the wire land, then with unsaved text asks save, discard or cancel: cancel returns false, discard reverts to the last confirmed text and puts the autosave to sleep until the next keystroke, and save proceeds only when the flush landed — a conflict answered with Cancel leaves the edit staged and the switch refused. The NC Code editor waits for a save on the wire, drains its debounced field save, and returns false when that save failed. The same gate runs before every mission row operation, not only before a selection change, because the operation's rebuild remounts the open editor and mission paths are index-based: a debounced save that outlived the remount would land on whichever command slid into the path it captured at mount. For the same reason both the NC Code editor and the list title cancel, never flush, on unmount. Display Labels nodeDisplayLabel(n) returns the translation of labelKey — with labelParams interpolated — when one is set, and the verbatim label otherwise. labelKey is therefore the form every role label the client translates itself takes, while label is the storage for text it cannot: server-composed mission titles, file-backed geometry paths and engine type names. The translator function is read inside the call rather than captured, so a language change re-renders the whole tree's role labels. Two labels are composed rather than looked up. A mission command's label is the title the server composes for it — the command's kind name in the request language, with the command's own text in brackets when there is one, as in Script [Warm-Up]. That title always arrives filled in, so the node's labelKey is always dropped and the tree's own kind-name fallback is a safety net that never fires in practice. Because titles are composed server-side per request, a language change also re-pulls the command entries and rewrites those labels in place. A file-backed geometry leaf carries its source file in brackets, so sibling instances read apart: StlFile [Geom/x.stl]. The voxel kind is renamed for display, appearing as MeshedGeomFile [...] rather than by its type name. Group stems take the same treatment for their intro text: infoKey wins over info, and a stem with neither falls back to a sentence naming the group. The Panel Host PrimarySlavePanel decides what the editor row shows, in this order: The three inline root types — MachineToolRoot, FixtureRoot, WorkpieceRoot — are rendered by the panel itself as a summary, and are never resolved from the registry. The two with a stand-alone file surface, Machine Tool and Fixture, carry an Object-Management button above it; the workpiece has none, since it is authored entirely through its child tree items. Otherwise the registry's panel for the selection's item type, mounted with the node as its only prop, with changed, type-changed, structure-changed, select-node and error wired to the host. A spinner while the first build is still running, and the select-an-item hint after that when the selection's type registers no panel. What decides a remount is the mounted component's key, ${id}|${key}|${stamp} — the node id, the node key, and the mission stamp where the node has one. So the editor remounts when the selection moves, when the bound object's key is re-minted, and when the Mission branch was rebuilt beneath it. That third term is exactly why the mission label refresh above mutates the node instead of rebuilding. The editor row carries nothing but the editor. The run controls sit in the tree pane instead: on the Execution page the Control Tree pane pins a run header above its tree scroller — the transport bar and the live execution-status badge — whatever the selection is. It rides the pane's content rather than the dock's expansion header because that header is the same component on General Setup, which renders neither piece. This is the page's sole ExecutionToolBar, so it owns the F5–F8 shortcuts, and because the dock keeps the tree pane mounted while its row is collapsed, a collapsed tree row does not drop them. When the tree column narrows, the six-button strip scrolls horizontally and the badge never shrinks, so the run state is the last thing a resize can hide. A pure Group stem is not a node without an editor. Group registers GroupInfoPanel, whose body is the stem's intro line followed by a clickable list of its children; a row click emits select-node and the host moves the selection there. The General Setup root, the two Anchor stems, the workpiece Material stem and the controller's two plane stems are all of this kind. The General Setup page adds a second slave, ContentSlavePanel, which resolves contentPanel from the same registry. Three item types declare one — the spindle root and its scalar and contour section types — and all three name the same contours view, so the charts stay mounted while the selection moves across the spindle branch: the component takes no props and is mounted unkeyed on purpose. Every other selection shows the column's empty hint. NodeTabCascade is the third consumer of the registry. It renders a branch as nested tabs rather than tree rows: the node's own panel on top, a single child inlined below it, several children as a dense tab strip in which only the active child mounts. The active tab is remembered per role path at module scope, with the per-tool segment wildcarded, so switching tools keeps every level's tab. Its panels report through an injected cascade host that carries the emitting node, because — unlike the tree's one-panel-at-a-time model — several panels are mounted at once. The Tick Column The tree runs a strict tick strategy, and a node hides its checkbox unless it is a mission command or a mission section that carries its own enable flag. Writing the ticked set walks every command node at any depth: a command whose state changed is PUT to the Mission API and, on success, has the new state copied onto its section children; a section whose state changed is dispatched to its kind's writer. A failed write raises a toast and leaves the model untouched, so the getter re-derives the old value and the box snaps back. The ticks share the mission operations' busy gate in both directions: a tick during a row operation is ignored — it would write to the node's pre-operation path — and the box snaps back the same way, while a tick's own writes hold the gate so no row operation can overtake them on the server and land the enable flag on whichever command slid into the ticked path. A row dims when it is itself disabled — a disabled command, or a section whose own flag is off — or when an ancestor command is disabled, which is how a disabled command greys its whole subtree while each descendant keeps its own state. The switch decides only whether the command runs: a disabled command stays fully editable. Layout Left Dock — both tree pages, one nav-bar button toggling the whole column Control Tree Expansion Row — collapses in place, keeping its header, which is the same page-neutral header on both pages; stays mounted while collapsed, so the tree keeps its scroll position and the run header keeps its shortcuts Run Header — Execution page only, pinned above the tree scroller and separated from it by a rule Execution Transport Bar — the six transport buttons; the strip scrolls horizontally when the column is narrower than it Execution Status Badge — the status label in its status colour; never shrinks Tree — the Execution page has two root rows, Mission above Program; the General Setup page has one, General Setup Drag Handle — on every mission command row, List rows included, immediately before the label. It is the first thing the row's own header renders, but the tree puts the expand arrow, on a row with children, and then the enable checkbox ahead of that header, so the handle sits to the checkbox's right rather than at the row's left edge. The Mission root row has none. While a drag is under way the dragged row dims, a line along the target row's top or bottom edge marks a before / after drop, and a tinted target row marks a drop into that list Node Row — the label is a real link to this node's ?tree= URL on the page, so the browser's context menu offers open-in-new-tab and copy-link; a plain left click keeps the in-app selection instead of navigating, while a modified or middle click opens a tab and leaves the current selection where it is. No node icons are rendered. Node CheckBox — mission command rows, and mission section rows carrying an enable flag Row Operations — on every mission command row, right-aligned: Move up, Move down, Duplicate and Delete. Absent from the layout at rest, so a resting label keeps the column's full width, and shown on the hovered row and on the selected row; on a device with no hover they are always shown. Move up is disabled on a list's first entry, Move down on its last, and all four while an operation is in flight Add Command — the + at the right edge of the Mission root row and of every List row, always visible, scoped to that row's list; disabled without an open project and while an operation is in flight. It opens the Add Command dialog — a search box over the command catalog, grouped by category, which fetches the catalog on every opening and accepts one pick per opening Spinner and “Loading project…” — shown instead of the tree until the first build lands Row Divider — a 5 px bar between the rows, shown only while both are open; dragging it upwards grows the editor row, which keeps a stored pixel height while the tree above absorbs the change, down to a 120 px editor floor and a 100 px tree floor Editor Expansion Row — its header carries the selection breadcrumb, the node path joined with slashes, and falls back to Editor; stays mounted while collapsed The selected node's editor panel, or “Select an item in the Control Tree to edit it here.” Content Column — General Setup page only, one nav-bar button The selected node's large content view, or “The selected item has no expanded content.” Both dock rows and both column widths are device-local browser preferences, shared by the two pages through one preferences module; each page keeps its own visibility record, and both pages share one expansion list because their id spaces do not overlap. Lifecycle The host is created while its page's script runs and provided before the dock mounts; the page's onMounted then awaits initialize(). That call connects the cleanup hub and builds the tree — on the equipment host, after re-indexing the machine tool, the workpiece and the fixture in that order — and finishes by adopting whatever the URL's ?tree= names. A loading flag is held for the whole call, which is what the tree and editor rows render their spinners from; later rebuilds mutate an already-populated tree and never re-enter it. A missing project, or a project without a fixture or workpiece, answers 404, and those are treated as empty states rather than errors, so no toast appears. Without an open project the Mission, Program and controller branches are still declared, as childless stems: their builders run only once a project is loaded. Because the layout keys its keep-alive wrapper on a project epoch, every page is destroyed and rebuilt when the project changes, and a host is therefore created once per project per page. Source Code Path See HiNC App Anatomy for git repository links. Web Application HiNC-2025-webservice (Quasar CLI SPA): wwwroot-src/src/components/controlTree/useControlTreeHost.ts — the host: the two scopes' root builders, the selection gate, the ?tree= sync, the mission ticks, the five mission row operations with their shared busy gate and id translation, the rebuild entry points, the re-index and Object-Management handlers, and the reactive surface the panes consume. wwwroot-src/src/components/controlTree/useMissionTreeDrag.ts — the drag-and-drop bookkeeping between mission rows: which rows drag, the drop mode from the pointer's position in the target row, and the row classes behind the drop indicators. wwwroot-src/src/components/controlTree/itemTypes.ts — the ControlNode and TreeItemDef shapes, the SlotCtx hooks, the structure-change payload, nodeDisplayLabel / nodeDisplayInfo, the geometry and transformer builders, the ITEM_TYPES map and buildSubtree. wwwroot-src/src/components/controlTree/ControlTreePanel.vue — the tree column: the Execution page's run header with the transport bar and the execution-status badge, the node anchors, the click handling that keeps a plain click in-app, the drag handles, the row operations, the Add Command + and the dialog it opens. wwwroot-src/src/components/execution/ExecutionToolBar.vue — the six transport buttons, and the F5–F8 shortcuts the sole instance registers. wwwroot-src/src/utils/executionStatusPresent.ts — the badge's status label and colour. wwwroot-src/src/components/controlTree/AddCommandDialog.vue — the search-first command picker over the server-served catalog. wwwroot-src/src/components/controlTree/ControlTreeDock.vue — the two-row dock and the height divider that sets the editor row's stored pixel height. wwwroot-src/src/components/controlTree/PrimarySlavePanel.vue — the panel host: the three inline root types, the registry lookup, the remount key and the gate registration. wwwroot-src/src/components/controlTree/ContentSlavePanel.vue — the General Setup content column and its unkeyed content panel. wwwroot-src/src/components/controlTree/GroupInfoPanel.vue — a group stem's intro and its navigating child list. wwwroot-src/src/components/controlTree/SoleEditorPanel.vue — a kind node's editor, resolved from the geometry and transformer editor maps. wwwroot-src/src/components/controlTree/NodeTabCascade.vue — the same branches rendered as nested tabs, with the remembered per-role tab and the cascade host injection. wwwroot-src/src/components/controlTree/missionItemTypes.ts — the Mission wave: node bookkeeping, the section table and its enable-flag readers and writers, the per-kind editors and display names. wwwroot-src/src/components/controlTree/programItemTypes.ts — the Program wave: the file tree from one response, and the writeback conversion nodes. wwwroot-src/src/components/controlTree/softNcItemTypes.ts — the controller wave: the two planes, the core leaves every runner grows, and the snapshot flags that decide which brand leaves join them. wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts — the Tool House wave and its tool- role paths. wwwroot-src/src/components/controlTree/runnerSuitItemTypes.ts — the two runner-suit leaves. wwwroot-src/src/components/controlTree/MissionRootPanel.vue — the Mission root's informational panel: the command count and the run-order hint. wwwroot-src/src/components/controlTree/ProgramRootPanel.vue — the Program root's summary panel and the refresh button that emits a payload-less structure-changed. wwwroot-src/src/components/controlTree/GeomCombinationTreePanel.vue — the combination's item list, whose add, remove and clear emit the same payload-less event. wwwroot-src/src/components/controlTree/MissionCommandSlavePanel.vue — a command's editor host: a List's Title field with its debounced save, and the only panel that exposes a dirty-switch gate. wwwroot-src/src/components/mission/ScriptCommandPanel.vue — the autosaving editor whose gate is forwarded, with its save / discard / cancel prompt. wwwroot-src/src/composables/useAutoSave.ts — the Script editor's autosave: the flush, the wait for a save on the wire, and the discard that sleeps the instance until the next edit. wwwroot-src/src/components/mission/NcCodeCommandPanel.vue — the second forwarded gate: the debounced field save it drains, and the unmount that cancels instead of flushing. wwwroot-src/src/components/mission/NcFileCommandPanel.vue — the one command editor that emits structure-changed, with the inserted range of its multi-pick. wwwroot-src/src/components/panels/PanelExpansion.vue — the expansion row both dock rows are built from. wwwroot-src/src/composables/useViewPrefs.ts — the device-local expansion list, last selections, dock sizes and the two runner-suit checkboxes. wwwroot-src/src/composables/useCleanupHub.ts — the key registration the builders call. wwwroot-src/src/router/treeRoutes.ts — the id migration hop and the page a given id belongs to. wwwroot-src/src/pages/ExecutionPage.vue — creates and provides the execution host. wwwroot-src/src/pages/GeneralSetupPage.vue — creates and provides the equipment host, and adds the content column. wwwroot-src/src/pages/ToolHousePage.vue — the registry consumer that renders tabs instead of a tree. wwwroot-src/src/layouts/MainLayout.vue — the project epoch that decides when a host is rebuilt. wwwroot-src/src/i18n/en/tree.ts — the dock labels, the group intros and the node role labels. See Also Tree Ids and Routes — how a node id becomes a URL, which page owns a given id, and how an older id keeps resolving Session State — the project epoch and the stores a host is rebuilt around Execution Page — the first live host: the run cockpit's Mission and Program branches General Setup Page — the second live host: the equipment branches and the content column Controller Branch — the one branch whose node set is not fixed: it is regrown from a snapshot, so which children exist depends on the controller in the project" + "summary": "Control Tree The Control Tree is the engine shared by the two tree-shaped pages of the web client: the Execution page at /execution and the General Setup page at /general-setup. Each page creates exactly one host — useControlTreeHost('execution') or useControlTreeHost('equipment') — provides it to its panes under one injection key, and the host owns everything after that: the node graph, the branch builders, the selection and the ?tree= query that carries it, the editor panel a selection resolves to, the mission enable ticks, and every structural operation on the Mission branch. The Tool House page at /tool-house reuses the same node shape and the same item-type registry but renders a branch as nested tabs and creates no host. Important Node ids are role paths, not identities that survive a version change. Anatomy makes no claim that a ?tree= id is stable across releases; see Tree Ids and Routes for the migration hop that keeps an older link resolving. The Node Every branch of every tree is built from one structure, ControlNode, declared in itemTypes.ts: id — the node's role path, slash-separated, whose first segment is the owning page's scope (execution/…, equipment/…, toolhouse/…). This is the addressing surface: the ?tree= query, the persisted expansion list and the persisted last selection all hold ids. The General Setup page's root carries its scope as its own id, equipment; the Execution page has no node with the bare execution id — its two roots are execution/mission and execution/program, and the segment is a scope key only. label, labelKey, labelParams — the display text; see Display Labels. itemType — the registry key that decides the node's editor and its child builder. key — the bound object. In the geometry and equipment branches it is an IndexService key, re-minted on every re-index; in the Mission branch it is the Mission API command path (0, 1, the dotted 0.2 of a nested list entry); in the Tool House branch it is the tool id as a string. Waves whose panels read a module-level state singleton rather than an indexed object leave it empty — the SoftNc controller leaves, the spindle sections, the Environment root's Ambient Temperature and Coolant leaves and the Program branch all do. ctx — the parent-provided SlotCtx: the afterChange commit chain, a slot's onCreate create-and-rebind hook, and a slot picker's allowedKinds / allowNone constraints. children — grown by the builders, not declared by the tree column. selectable, info / infoKey, and the mission / program bookkeeping records the Mission and Program waves stamp on their own nodes. The split between id and key is the load-bearing one. A key is re-minted every time the host re-indexes the model, so nothing durable may hang off it; an id names a role in the model and therefore survives a rebuild, which is why expansion state, the URL and the landing selection are all keyed on ids. Two id families are positional rather than role-based: Mission entries are ${parentId}/${index} and Program files are ${parentId}/${index}, so moving or deleting a mission command renumbers its siblings and a link to one names a position in the list rather than that command. The host keeps three id sets of its own that must follow the rows rather than the numbers — the persisted expansion list, the Add Command focus and the selection — and translates all three through every mission row operation it runs; see the row operations. The Item-Type Registry ITEM_TYPES maps an itemType string onto a TreeItemDef carrying up to three members: panel — the editor mounted in the dock's editor row for a node of this type. contentPanel — a large view for the General Setup page's content column. buildChildren — an async builder that returns this node's children. Two flavours of type share the map. Slot types (Geometry, Transformer) have a kind picker as their panel and grow at most one child, the concrete kind, at the kind-independent id ${slot.id}/type — so switching a slot's kind keeps both the selection and the expansion. A slot holding nothing grows no child at all, which for the four geometry slots whose picker offers None is an ordinary state rather than a failure. Kind types (Box3d, StaticTranslation, …) register SoleEditorPanel, which looks the concrete editor up in the geometry and transformer editor maps and binds it to the node's key. The two composite geometry kinds do not embed nested editors: TransformationGeom grows an inner-geometry and an inner-transformer slot, and GeomCombination grows one slot per item, so the tree owns the structure and every panel stays shallow. The map is one flat namespace assembled in itemTypes.ts: the Group stem type and the geometry, transformer, workpiece-leaf, thermal-condition and spindle entries are written inline, and five per-wave registries are spread in beside them. The Execution page's two roots are registry types — MissionRoot and ProgramRoot, from their waves — and no wrapper type stands over them. The three roots the panel host renders itself — Machine Tool, Fixture and Workpiece — have no entry here at all. Wave File What it contributes Mission missionItemTypes.ts MissionRoot, whose panel is informational — the command count and the run-order hint that names the row affordances; MissionCommand, whose panel is the kind's editor, or only a Title field for a List; MissionSection; section children at ${command.id}/${sectionId}; the per-kind bespoke editors, with a generic field editor as the fallback Program programItemTypes.ts ProgramRoot, ProgramFile, ProgramConversionFile; writeback conversions at ${root.id}/dst-${index} Tool House toolHouseItemTypes.ts the tool collection and the per-tool editor branches under toolhouse/tool- /… SoftNc controller softNcItemTypes.ts the controller root and its leaves on two planes — …/machine/ and …/program-data/ — a core every runner grows plus the brand-driven ones Runner suits runnerSuitItemTypes.ts CsvRunnerRoot and ClRunnerRoot, flat single-panel leaves with no builder The Program branch is fetched whole: its root builder takes one file-tree response plus one conversions response and stashes each file's raw subtree on the node, so the file nodes' builder only maps what is already in hand. The SoftNc branch is the opposite — its builder reads the runner snapshot once, and with no runner installed grows nothing at all. Where one resolves, the two plane stems appear over a fixed core that stands for every brand: six machine leaves, and Work Coordinates and Tool Offsets on the program-data plane. The leaves beside that core are the brand-driven ones — each appears only where the snapshot reports its backing table, so a brand switch changes which nodes exist. One flag does double duty: the Siemens $TC_DP flag adds its own two leaves and renames the core Tool Offsets leaf to its ISO G43 H reading, so the two offset ledgers do not read as one. The two runner-suit nodes are conditional, and the host — not the registry — decides. With a project open, a CSV or CL controller node is built when its Preference checkbox is on, or when the current ?tree= value starts with that node's id. The checkbox is device-local and off by default; the route is the only other reveal, deliberately not the persisted last selection, so a node switched off while it is selected does not resurrect itself. Stepping off comes first: when the selection sits on a node the user has just unchecked, the host re-points the URL at the page root before rebuilding. Building a Branch buildSubtree(node, services, depth) is the whole builder. It looks the node's type up, returns without touching children when the type declares no buildChildren or when depth has reached MAX_DEPTH (12, a guard against a self-referencing model), and otherwise awaits the builder, recurses into each returned child, and assigns the result. Building is eager: a branch is materialised in full at build time rather than lazily on expansion. Builders receive one service, registerKey, which registers a freshly minted IndexService key with the page's cleanup hub — see Webapi with Hub-Cleanup Assistance. rebuildBranch(node) is buildSubtree plus one thing: it adds the node's id to the expansion list so the fresh children are visible, and reports a failure as a toast named after the node's display label. The structure-changed event A panel that has changed the shape of the model emits structure-changed (or type-changed, wired to the same handler). The optional payload is a StructureChangeRequest: scopeId — the branch to rebuild. Without it the scope is the selected node itself, which is correct only while the change stays inside the emitting panel's own branch. selectId — the selection to adopt afterwards. It is assigned directly, bypassing the dirty-switch gate, because the emitting panel is being replaced on purpose. A null clears the selection. inserted — entries a panel inserted into a mission list itself: the list node's id, the child index the run starts at and its count. The host then treats the rebuild as a mission operation — it holds the busy gate and slides its index-based ids past the new siblings — rather than as a plain branch refresh. One command editor emits the event: the Program File editor, whose multi-pick turns every extra file into a new Program File command inserted right after it, in pick order; the command panel hosting it re-scopes the event to the parent list, keeps that command selected and passes the insert range along. Two panels emit it with no payload and so take the default scope, their own node: the Program root panel's refresh button, which re-reads the file tree from the current session and rebuilds the Program branch through rebuildBranch, so the branch opens under it; and the GeomCombination item panel after an item add, an item remove or a clear, since its item slots must be regrown. The controller brand switch and the runner's Object-Management install re-scope to the controller root. The Tool House type selectors and a flute add re-scope to their own node; everything that rewrites the tool collection — a new tool, a duplicate, a delete, an id rename, an Object-Management install — re-scopes to the tool-house root, and a flute delete re-scopes to its fluting parent. Every other structural change to the Mission branch is an operation of the host itself, not an event, because the tree rows are the only surface that offers it: Add Command, a drag between rows, Move up / Move down, Duplicate and Delete. A drag is HTML5 drag-and-drop between mission rows; every command row drags, the Mission root row only receives, and where the pointer sits in the target row decides the operation. A plain command row has no edge band: it splits at its midline, the upper half putting the dragged command before that row and the lower half after it — a reorder when both share a list, a relocation across lists otherwise. A List row keeps that before / after reading only in its top and bottom quarters; its middle half, and the whole of the Mission root row, take the command into that list, at the tail. A drop onto the dragged row's own subtree is refused, and a drop aborts when a rebuild mid-drag re-stamped the dragged node, since its id may then name another command. All five run through one helper that holds a busy gate (one operation at a time), runs the open panel's dirty-switch gate, calls the Mission API, translates the expansion list and the Add Command focus through the operation, rebuilds the branch of the list or lists it rewrote — the one list, or the nearest list above both ends of a cross-list drag — and only then translates the selection and names any post-operation selection, since the ids it names exist only after the rebuild. A refused gate drops the operation and says so in a notification (\"Cancelled — the open editor keeps its unsaved edits.\"); the delete's own confirm dialog runs before the gate, so a cancelled delete forces no save prompt on the open editor. The selection moves only when it rides on the acted-on row — that row itself, or a section or nested entry under it. Then it follows a stepped or dragged command, lands on the clone after a duplicate, and after a delete lands on the nearest remaining entry of that list, or on the list node itself once the list is empty. Otherwise the editor the user is in stays on its own, re-indexed row. Add Command never moves the selection: it reveals the new row and makes it the focus, so a run of adds lands in order. The focus is the command most recently selected — a section row counts for its owning command — or the last one added, and an Add Command from a list row's + inserts right after that focus when the focus is a direct entry of that list, and at the list's tail otherwise; the Mission root row's + therefore never chases a focus inside a nested list. Whole-tree rebuilds, and the refreshes that are not rebuilds rebuildTree() replaces the root array outright, and runs after an Object-Management swap of the machine tool or the fixture, after a blank machining chain is created, and after either runner-suit preference flips. On the execution host, an execution-status transition re-runs buildSubtree on the Program root directly rather than through rebuildBranch, so a run does not force that branch open on every transition. Two refreshes deliberately mutate existing nodes instead of rebuilding: A mission command's title is re-read from the entry list and written onto the node's label. A file-backed geometry leaf's label is re-read when its source file changes. The mission one exists because a rebuild of the Mission branch re-mints the per-build stamp that forms part of the editor's remount key, and remounting an open editor mid-edit would cost the user their cursor and any staged autosave. The geometry one is the same principle without the stamp: a title change and a source-file change alter no structure, so the label is all that has to move, and replacing the node under an open file editor would buy nothing. The commit chain The tree has no component bubbling, so the full post-edit commit chain lives on each node as ctx.afterChange, composed level by level as the branch is built. A GeomCombination item's chain cleans that combination's aggregated cache before running its parent's chain; the fixture's chain ends in a geometry-cache clear; the two workpiece geometry slots re-commit the swap-in before clearing their own cache, and skip that re-commit when the slot has been set to none; the fixture's two anchor transformers re-commit and then clear the geometry cache, while the workpiece's two re-commit and clear nothing, since a placement change invalidates no cached solid. Tool-house nodes all share one refresh. Every other family carries a no-op: the Mission, Program, spindle, SoftNc and thermal-condition nodes and the workpiece's Mesh and Material leaves have panels that write straight to the model, and the pages' canvases draw that model; the group stems and the Machine Tool and Workpiece roots have no field editor to commit for at all. Selection and the Dirty-Switch Gate Every selection change funnels through requestSelect(id). It returns immediately when the id is already selected; it refuses outright while a mission row operation, or a tick's own writes, are in flight — the operation ends by naming the post-operation selection, which would silently undo a change landed during its rebuild; otherwise it awaits the mounted panel's optional tryConsumeBeforeSwitch() and abandons the switch when that returns false. Three entrances use it: a click in the tree, a change to the URL's ?tree= value, and a select-node event from the mounted panel — the wire the panel host puts on every registry panel, so a group stem's child list and the Program branch's conversion jumps both arrive through that one. Two paths assign the selection directly and skip the gate: the selectId of a structure change, and the post-operation selection of a mission row operation, which has already run the gate itself. There is no “nothing selected” state. Re-clicking the selected row makes the tree yield null, and that is ignored; an empty ?tree= lands on the persisted last selection for that page when the built tree still contains it, and otherwise on the page's root — General Setup on the equipment host, and Mission, the first of its two roots, on the execution host. The editor row is therefore always alive, and reclaiming its height is the row's own collapse toggle rather than a deselection. The gate itself is registered by the panel host: the mounted registry panel is handed to the host through a template ref, and the host asks that instance for tryConsumeBeforeSwitch. Panels that write one field per request need no gate and register none. One panel exposes it — MissionCommandSlavePanel: on a list entry it waits for a title save already on the wire, then flushes the debounced title save while the command path is still live, and allows the switch only when that save landed; on any other entry it forwards its inner editor's gate. Two editors have one. The Script editor first lets a save already on the wire land, then with unsaved text asks save, discard or cancel: cancel returns false, discard reverts to the last confirmed text and puts the autosave to sleep until the next keystroke, and save proceeds only when the flush landed — a conflict answered with Cancel leaves the edit staged and the switch refused. The NC Code editor waits for a save on the wire, drains its debounced field save, and returns false when that save failed. The same gate runs before every mission row operation, not only before a selection change, because the operation's rebuild remounts the open editor and mission paths are index-based: a debounced save that outlived the remount would land on whichever command slid into the path it captured at mount. For the same reason both the NC Code editor and the list title cancel, never flush, on unmount. Display Labels nodeDisplayLabel(n) returns the translation of labelKey — with labelParams interpolated — when one is set, and the verbatim label otherwise. labelKey is therefore the form every role label the client translates itself takes, while label is the storage for text it cannot: server-composed mission titles, file-backed geometry paths and engine type names. The translator function is read inside the call rather than captured, so a language change re-renders the whole tree's role labels. Two labels are composed rather than looked up. A mission command's label is the title the server composes for it — the command's kind name in the request language, with the command's own text in brackets when there is one, as in Script [Warm-Up]. That title always arrives filled in, so the node's labelKey is always dropped and the tree's own kind-name fallback is a safety net that never fires in practice. Because titles are composed server-side per request, a language change also re-pulls the command entries and rewrites those labels in place. A file-backed geometry leaf carries its source file in brackets, so sibling instances read apart: StlFile [Geom/x.stl]. The voxel kind is renamed for display, appearing as MeshedGeomFile [...] rather than by its type name. Group stems take the same treatment for their intro text: infoKey wins over info, and a stem with neither falls back to a sentence naming the group. The Panel Host PrimarySlavePanel decides what the editor row shows, in this order: The three inline root types — MachineToolRoot, FixtureRoot, WorkpieceRoot — are rendered by the panel itself as a summary, and are never resolved from the registry. The two with a stand-alone file surface, Machine Tool and Fixture, carry an Object-Management button above it; the workpiece has none, since it is authored entirely through its child tree items. Otherwise the registry's panel for the selection's item type, mounted with the node as its only prop, with changed, type-changed, structure-changed, select-node and error wired to the host. A spinner while the first build is still running, and the select-an-item hint after that when the selection's type registers no panel. What decides a remount is the mounted component's key, ${id}|${key}|${stamp} — the node id, the node key, and the mission stamp where the node has one. So the editor remounts when the selection moves, when the bound object's key is re-minted, and when the Mission branch was rebuilt beneath it. That third term is exactly why the mission label refresh above mutates the node instead of rebuilding. The editor row carries nothing but the editor. The run controls sit in the tree pane instead: on the Execution page the Control Tree pane pins a run header above its tree scroller — the transport bar and the live execution-status badge — whatever the selection is. It rides the pane's content rather than the dock's expansion header because that header is the same component on General Setup, which renders neither piece. This is the page's sole ExecutionToolBar, so it owns the F5–F8 shortcuts, and because the dock keeps the tree pane mounted while its row is collapsed, a collapsed tree row does not drop them. When the tree column narrows, the six-button strip scrolls horizontally and the badge never shrinks, so the run state is the last thing a resize can hide. A pure Group stem is not a node without an editor. Group registers GroupInfoPanel, whose body is the stem's intro line followed by a clickable list of its children; a row click emits select-node and the host moves the selection there. The General Setup root, the two Anchor stems, the workpiece Material stem and the controller's two plane stems are all of this kind. The General Setup page adds a second slave, ContentSlavePanel, which resolves contentPanel from the same registry. Three item types declare one — the spindle root and its scalar and contour section types — and all three name the same contours view, so the charts stay mounted while the selection moves across the spindle branch: the component takes no props and is mounted unkeyed on purpose. Every other selection shows the column's empty hint. NodeTabCascade is the third consumer of the registry. It renders a branch as nested tabs rather than tree rows: the node's own panel on top, a single child inlined below it, several children as a dense tab strip in which only the active child mounts. The active tab is remembered per role path at module scope, with the per-tool segment wildcarded, so switching tools keeps every level's tab. Its panels report through an injected cascade host that carries the emitting node, because — unlike the tree's one-panel-at-a-time model — several panels are mounted at once. The Tick Column The tree runs a strict tick strategy, and a node hides its checkbox unless it is a mission command or a mission section that carries its own enable flag. Writing the ticked set walks every command node at any depth: a command whose state changed is PUT to the Mission API and, on success, has the new state copied onto its section children; a section whose state changed is dispatched to its kind's writer. A failed write raises a toast and leaves the model untouched, so the getter re-derives the old value and the box snaps back. The ticks share the mission operations' busy gate in both directions: a tick during a row operation is ignored — it would write to the node's pre-operation path — and the box snaps back the same way, while a tick's own writes hold the gate so no row operation can overtake them on the server and land the enable flag on whichever command slid into the ticked path. A row dims when it is itself disabled — a disabled command, or a section whose own flag is off — or when an ancestor command is disabled, which is how a disabled command greys its whole subtree while each descendant keeps its own state. The switch decides only whether the command runs: a disabled command stays fully editable. Layout Left Dock — both tree pages, one nav-bar button toggling the whole column Control Tree Expansion Row — collapses in place, keeping its header, which is the same page-neutral header on both pages; stays mounted while collapsed, so the tree keeps its scroll position and the run header keeps its shortcuts Run Header — Execution page only, pinned above the tree scroller and separated from it by a rule Execution Transport Bar — the six transport buttons; the strip scrolls horizontally when the column is narrower than it Execution Status Badge — the status label in its status colour; never shrinks Tree — the Execution page has two root rows, Mission above Program; the General Setup page has one, General Setup Drag Handle — on every mission command row, List rows included, immediately before the label. It is the first thing the row's own header renders, but the tree puts the expand arrow, on a row with children, and then the enable checkbox ahead of that header, so the handle sits to the checkbox's right rather than at the row's left edge. The Mission root row has none. While a drag is under way the dragged row dims, a line along the target row's top or bottom edge marks a before / after drop, and a tinted target row marks a drop into that list Node Row — the label is a real link to this node's ?tree= URL on the page, so the browser's context menu offers open-in-new-tab and copy-link; a plain left click keeps the in-app selection instead of navigating, while a modified or middle click opens a tab and leaves the current selection where it is. No node icons are rendered. Node CheckBox — mission command rows, and mission section rows carrying an enable flag Row Operations — on every mission command row, right-aligned: Move up, Move down, Duplicate and Delete. Absent from the layout at rest, so a resting label keeps the column's full width, and shown on the hovered row and on the selected row; on a device with no hover they are always shown. Move up is disabled on a list's first entry, Move down on its last, and all four while an operation is in flight Add Command — the + at the right edge of the Mission root row and of every List row, always visible, scoped to that row's list; disabled without an open project and while an operation is in flight. It opens the Add Command dialog — a search box over the command catalog, grouped by category, which fetches the catalog on every opening and accepts one pick per opening Spinner and “Loading project…” — shown instead of the tree until the first build lands Row Divider — a 5 px bar between the rows, shown only while both are open; dragging it upwards grows the editor row, which keeps a stored pixel height while the tree above absorbs the change, down to a 120 px editor floor and a 100 px tree floor Editor Expansion Row — its header carries the selection breadcrumb, the node path joined with slashes, and falls back to Editor; stays mounted while collapsed The selected node's editor panel, or “Select an item in the Control Tree to edit it here.” Content Column — General Setup page only, one nav-bar button The selected node's large content view, or “The selected item has no expanded content.” Both dock rows and both column widths are device-local browser preferences, shared by the two pages through one preferences module; each page keeps its own visibility record, and both pages share one expansion list because their id spaces do not overlap. Lifecycle The host is created while its page's script runs and provided before the dock mounts; the page's onMounted then awaits initialize(). That call connects the cleanup hub and builds the tree — on the equipment host, after re-indexing the machine tool, the workpiece and the fixture in that order — and finishes by adopting whatever the URL's ?tree= names. A loading flag is held for the whole call, which is what the tree and editor rows render their spinners from; later rebuilds mutate an already-populated tree and never re-enter it. A missing project, or a project without a fixture or workpiece, answers 404, and those are treated as empty states rather than errors, so no toast appears. Without an open project the Mission, Program and controller branches are still declared, as childless stems: their builders run only once a project is loaded. Because the layout keys its keep-alive wrapper on a project epoch, every page is destroyed and rebuilt when the project changes, and a host is therefore created once per project per page. Source Code Path See HiNC App Anatomy for git repository links. Web Application HiNC-2025-webservice (Quasar CLI SPA): wwwroot-src/src/components/controlTree/useControlTreeHost.ts — the host: the two scopes' root builders, the selection gate, the ?tree= sync, the mission ticks, the five mission row operations with their shared busy gate and id translation, the rebuild entry points, the re-index and Object-Management handlers, and the reactive surface the panes consume. wwwroot-src/src/components/controlTree/useMissionTreeDrag.ts — the drag-and-drop bookkeeping between mission rows: which rows drag, the drop mode from the pointer's position in the target row, and the row classes behind the drop indicators. wwwroot-src/src/components/controlTree/itemTypes.ts — the ControlNode and TreeItemDef shapes, the SlotCtx hooks, the structure-change payload, nodeDisplayLabel / nodeDisplayInfo, the geometry and transformer builders, the ITEM_TYPES map and buildSubtree. wwwroot-src/src/components/controlTree/ControlTreePanel.vue — the tree column: the Execution page's run header with the transport bar and the execution-status badge, the node anchors, the click handling that keeps a plain click in-app, the drag handles, the row operations, the Add Command + and the dialog it opens. wwwroot-src/src/components/execution/ExecutionToolBar.vue — the six transport buttons, and the F5–F8 shortcuts the sole instance registers. wwwroot-src/src/utils/executionStatusPresent.ts — the badge's status label and colour. wwwroot-src/src/components/controlTree/AddCommandDialog.vue — the search-first command picker over the server-served catalog. wwwroot-src/src/components/controlTree/ControlTreeDock.vue — the two-row dock and the height divider that sets the editor row's stored pixel height. wwwroot-src/src/components/controlTree/PrimarySlavePanel.vue — the panel host: the three inline root types, the registry lookup, the remount key and the gate registration. wwwroot-src/src/components/controlTree/ContentSlavePanel.vue — the General Setup content column and its unkeyed content panel. wwwroot-src/src/components/controlTree/GroupInfoPanel.vue — a group stem's intro and its navigating child list. wwwroot-src/src/components/controlTree/SoleEditorPanel.vue — a kind node's editor, resolved from the geometry and transformer editor maps. wwwroot-src/src/components/controlTree/NodeTabCascade.vue — the same branches rendered as nested tabs, with the remembered per-role tab and the cascade host injection. wwwroot-src/src/components/controlTree/missionItemTypes.ts — the Mission wave: node bookkeeping, the section table and its enable-flag readers and writers, the per-kind editors and display names. wwwroot-src/src/components/controlTree/programItemTypes.ts — the Program wave: the file tree from one response, and the writeback conversion nodes. wwwroot-src/src/components/controlTree/softNcItemTypes.ts — the controller wave: the two planes, the core leaves every runner grows, and the snapshot flags that decide which brand leaves join them. wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts — the Tool House wave and its tool- role paths. wwwroot-src/src/components/controlTree/runnerSuitItemTypes.ts — the two runner-suit leaves. wwwroot-src/src/components/controlTree/MissionRootPanel.vue — the Mission root's informational panel: the command count and the run-order hint. wwwroot-src/src/components/controlTree/ProgramRootPanel.vue — the Program root's summary panel and the refresh button that emits a payload-less structure-changed. wwwroot-src/src/components/controlTree/GeomCombinationTreePanel.vue — the combination's item list, whose add, remove and clear emit the same payload-less event. wwwroot-src/src/components/controlTree/MissionCommandSlavePanel.vue — a command's editor host: a List's Title field with its debounced save, and the only panel that exposes a dirty-switch gate. wwwroot-src/src/components/mission/ScriptCommandPanel.vue — the autosaving editor whose gate is forwarded, with its save / discard / cancel prompt. wwwroot-src/src/composables/useAutoSave.ts — the Script editor's autosave: the flush, the wait for a save on the wire, and the discard that sleeps the instance until the next edit. wwwroot-src/src/components/mission/NcCodeCommandPanel.vue — the second forwarded gate: the debounced field save it drains, and the unmount that cancels instead of flushing. wwwroot-src/src/components/mission/NcFileCommandPanel.vue — the one command editor that emits structure-changed, with the inserted range of its multi-pick. wwwroot-src/src/components/panels/PanelExpansion.vue — the expansion row both dock rows are built from. wwwroot-src/src/composables/useViewPrefs.ts — the device-local expansion list, last selections, dock sizes and the two runner-suit checkboxes. wwwroot-src/src/composables/useCleanupHub.ts — the key registration the builders call. wwwroot-src/src/router/treeRoutes.ts — the id migration hop and the page a given id belongs to. wwwroot-src/src/pages/ExecutionPage.vue — creates and provides the execution host. wwwroot-src/src/pages/GeneralSetupPage.vue — creates and provides the equipment host, and adds the content column. wwwroot-src/src/pages/ToolHousePage.vue — the registry consumer that renders tabs instead of a tree. wwwroot-src/src/layouts/MainLayout.vue — the project epoch that decides when a host is rebuilt. wwwroot-src/src/i18n/en/tree.ts — the dock labels, the group intros and the node role labels. See Also Tree Ids and Routes — how a node id becomes a URL, which page owns a given id, and how an older id keeps resolving Session State — the project epoch and the stores a host is rebuilt around Execution Page — the first live host: the run cockpit's Mission and Program branches General Setup Page — the second live host: the equipment branches and the content column Controller Branch — the one branch whose node set is not fixed: it is regrown from a snapshot, so which children exist depends on the controller in the project" }, "anatomy/platform/i18n.html": { "href": "anatomy/platform/i18n.html", @@ -362,7 +362,7 @@ "anatomy/platform/tree-ids-and-routes.html": { "href": "anatomy/platform/tree-ids-and-routes.html", "title": "Tree Ids and Routes | HiAPI-C# 2025", - "summary": "Tree Ids and Routes The web client addresses itself with two things: a vue-router path, and — on the two Control-Tree pages — a tree query argument naming the selected tree node, as in /general-setup?tree=equipment/fixture/geometry. This page is the reference for both surfaces: the route table, the redirect-only paths that keep older bookmarks resolving, the id-migration chain, and the resolver that decides which page owns a given ?tree= id. The router runs in HTML5 history mode, so every one of these paths is a real URL the server has to answer. Important Nothing here promises that a Control-Tree id is stable. The guarantee is narrower and exact: an id keeps resolving, because every regroup adds a migration hop to migrateLegacyTreeId rather than rewriting the previous one. The ids themselves have moved repeatedly, and a page that quotes one is quoting a value that can move again. The Route Table / is the shell-layout record itself; every route below it except the login and catch-all records is one of its children, so each renders inside the Main Panel's frame and menu bar. Path Route name What it owns / — The shell layout. It carries no page of its own; its empty child redirects to the Execution route. /execution execution The run cockpit and the Execution Control Tree, whose selection rides ?tree=execution/…. /general-setup general-setup The equipment Control Tree, whose selection rides ?tree=equipment/…. /machine-tool machine-tool The machining chain on a canvas of its own, beside a left column that shows either a read-only identity panel or the chain's XML source — two states of one column, chosen with a GUI/XML toggle. A load button installs a chain file into the project. Carries no Page-menu entry and is reached by URL. /tool-house/:toolId(\\d+)?/:tab?/:subtab? tool-house The tool library and the per-tool editor. The three optional segments carry the selected tool and the two nested tab levels. /preference/log preference-log The Log Viewer, reached from the menu bar's Show Log button. It is not under /util/. /util/file-explorer/:location(.*)* util-file-explorer The File Explorer. Its catch-all mirrors the browsed location — root display name followed by the relative segments — into the path. /util/mech-builder util-mech-builder The Mechanism Builder. /login login The sign-in form. It sits outside the shell layout and carries its own Quasar layout. /:catchAll(.*)* — The 404 page, likewise outside the shell layout: it prints the unmatched full path and offers one button back to the Execution route. The menu bar's Page dropdown holds every one of these that is menu-reachable, in setup order: Tool House, General Setup and Execution, then File Explorer and Mechanism Builder below a separator. The Log Viewer has a button of its own rather than a menu entry, and /machine-tool has neither — it is reached by URL. The Tool House route's tool segment is constrained to digits, but all three of its segments are optional, so a non-numeric segment in the tool position is not rejected: the router skips the tool parameter and reads that segment as the tab, which is what makes /tool-house/cutter a working tab deep link with no tool named. The consequence is that the record absorbs three segments when the first is a number and only two when it is not, and a URL carrying more than the record can absorb — /tool-house/abc/def/ghi — falls through to the catch-all. An unrecognised tab name is not an error either: the page canonicalises it to that level's default, as The Tool House Translation sets out. Redirect-Only Paths These records carry no component. They exist so that a link minted before the corresponding editor moved into a Control Tree still lands on the editor. Path Lands on /controller/:rest(.*)* /general-setup?tree=equipment/controller — any trailing path is discarded, the retired Controller page's / segment included, so every form lands on the branch root. /spindle-capability/:tab? /general-setup?tree=equipment/spindle, with / appended when the segment is one of thermal, gear-shift, dry-run, power, torque. An unrecognised segment is dropped and the branch root is selected. /equipment/spindle /general-setup?tree=equipment/spindle /fixture/:rest(.*)* /general-setup?tree=equipment/fixture — any trailing path is discarded. /workpiece/:rest(.*)* /general-setup?tree=equipment/workpiece — any trailing path is discarded. /equipment/background-coolant /general-setup?tree=equipment/background. Background and Coolant are two separate tree nodes; the redirect picks Background. /mission /execution?tree=execution/mission The five spindle tab names are declared in treeRoutes.ts as SPINDLE_TABS, and imported by wwwroot-src/src/router/routes.ts — which is the list the redirect tests its :tab? segment against. The equipment tree does not import that constant: it spells the same five segments as literals while building the equipment/spindle/ children, so redirect and branch agree by convention rather than through a shared list — renaming a spindle section is therefore an edit in two places. The Tool House name lists below are the other case, genuinely shared. The ?tree= Query Selection and URL are synced two ways by the Control-Tree host, one instance per tree page. URL to selection. A watcher on the query drives applyRouteSelection(), and it is registered immediate, so an id belonging to another page redirects on the first tick rather than after this page's first tree build. The host also calls the same function once the tree has actually been built, which is when a deep link can finally be honoured. Selection to URL. A watcher on the selected id replaces the tree argument, preserving the rest of the query. It uses router.replace, so browsing the tree does not fill the browser's history with one entry per node. The comparison that breaks the loop is made against the raw query rather than the migrated form, which is what makes an older id canonicalise: opening ?tree=controller selects the node and then rewrites the URL to ?tree=equipment/controller. Neither watcher touches the URL unless the current route name is the page's own. The shell layout keeps every visited page alive, so a host whose page is not showing keeps receiving route changes, and without the guard it would write another page's URL. The selection watcher does one thing before that guard: it records the id as this page's last selection. That ordering is load-bearing, because a selection can move while its page is off screen — unticking a CSV or CL Controller checkbox steps the equipment host off that node onto the equipment root, and the Preference menu that carries those checkboxes is open on every page — and the landing selection has to have followed it. That same checkbox flip is a third writer of the tree argument, and the one place the guard is absent. The equipment host watches both checkboxes, and when the standing selection is a node the flip removes, it replaces tree with equipment — the rest of the query preserved — before stepping the selection off. The route name is not consulted there, so the replacement goes to whichever route is showing. What applyRouteSelection Does The change is ignored unless this page owns the current route. The raw query is migrated into today's id. If its first segment names a different page and that segment is one of the known roots, the location is replaced with the route that owns it and the pass stops. An empty query falls back to the landing selection: the persisted last id for this page when that id exists in the tree just built, otherwise the page's root node — which is always present once the tree is built, so the editor column always has something to show. An id the built tree does not contain is ignored — the current selection stands and the URL keeps the unrecognised value until the next selection overwrites it. This is deliberate: the redirect in step 2 fires only for known roots, because sending an unroutable id back to the same page would loop. Otherwise every ancestor prefix of the id is added to the expanded set so the node is visible, and the selection is requested through the same gate a tree click uses. A panel holding unsaved edits may refuse the switch, and a refusal re-points the URL at the selection that actually stands. The Id the URL Names, Before the Tree Exists treePathOfRoute() — the raw query put through migrateLegacyTreeId — is not read only by the selection logic. The equipment tree consults it while it is being built, to decide whether to materialise the CSV Controller and CL Controller nodes: each is normally shown only when its Preference checkbox is ticked, and a URL naming one reveals it regardless. That reveal has to happen at build time precisely because step 4 above refuses an id the built tree lacks, so a bookmark to a switched-off node would otherwise dead-end. Only the URL reveals a node this way; the persisted last selection does not, so a node the user has just unticked while standing on it does not resurrect itself. Id Migration migrateLegacyTreeId is one pass of ordered guards over the whole id; the first that matches returns, and an id matching none is returned unchanged. An id shaped like Becomes controller, controller/… equipment/controller, equipment/controller/… spindle, spindle/… equipment/spindle, equipment/spindle/… mission, mission/… execution/mission, execution/mission/… equipment/mission, equipment/mission/… execution/mission, execution/mission/… any id ending in /contours/tray, or containing /contours/tray/ the same id with that segment spelled fluting The last rule renames one segment in place and leaves its children — baseline, flute-, side, bottom — untouched, so a deep link into a flute contour survives the engine's Fluting type naming. The two mission rules cover the two id shapes separately rather than chaining, because the first matching guard returns. The function is applied at four points, which is what makes the guarantee hold in practice: to the raw ?tree= query, on every read; to the persisted last selection, before it is looked up in the tree; to the persisted list of expanded node ids, once when a host is constructed, so an older expansion set still unfolds the branches it names; as the first step of routeForTreeId, so the id-to-page resolver never sees an unmigrated id. Note what the first rule implies: a bare ?tree=controller selects the equipment/controller branch — the controller editor on the General Setup page — and the redirect-only /controller path above lands on the same branch, so a bookmark from the retired Controller page's era resolves in either form. Landing an Id on Its Page TREE_PAGE_ROOTS lists the first segments that name a page: execution, equipment and toolhouse. spindle is absent on purpose — migration folds it into equipment/… before any root check runs, so no root check ever sees it. routeForTreeId migrates the id, then dispatches on its first segment: toolhouse — the Tool House route, with the id's segments translated into path params (below). equipment — the General Setup route, carrying the migrated id as ?tree=. anything else — the Execution route, carrying the migrated id as ?tree=. This is a fall-through, not a test for execution, so an unrecognised id handed to this function lands on the Execution page. Reaching it with a genuinely unroutable id is prevented upstream: the host calls the function only for ids whose root is in TREE_PAGE_ROOTS. The returned location replaces the whole current location. Only the tree argument survives the hop; any other query argument on the URL being redirected away from is dropped, and the Tool House form carries no query at all. The Tool House Translation The Tool House page keeps its state in path segments rather than a query, so an id arriving from another page has to be translated. routeForTreeId walks the segments of toolhouse/tool- / / : segment two contributes toolId when it is tool- followed by an integer; segment three contributes tab when it is one of general, cutter, holder, clamping, intelligent; segment four contributes subtab when it is one of the cutter sections — material, profile, contours, upper-beam, opt — or one of the holder sections, geometry and resolution. Only the sub-tab step is nested inside the tab step: an unrecognised tab discards the sub-tab with it, whereas the tool step is tested on its own, so a second segment that is not tool- costs the toolId param alone and the tab still translates. Everything deeper than the last segment the URL can carry is discarded either way — an id pointing at a single flute contour under …/cutter/contours/fluting/… lands on the nearest tab the URL can express. The same three name lists are imported by the page itself, so the tab set and the translation cannot drift apart. Once on the page, the tab segments are kept in step with the tabs by useRouteTabs, a composable whose only consumer this page is. It gives each tab level one route param, a valid-name set and a default; a nested level may declare which parent values make it apply, and while its parent is something else the level is dormant — its segment is dropped from the URL while its reference quietly remembers the last value, so returning to that parent tab returns to the sub-tab it had. The Tool House sub-tab level applies under cutter and holder only, and both its valid set and its default depend on which of the two is showing. A segment the level does not recognise resolves to that default rather than failing. Canonicalisation runs on the first mount and on every keep-alive re-entry, which is why a bare /tool-house acquires its tab segments. The tool segment is not one of the composable's levels: the page fills it in itself, adopting the URL's tool when the project holds it and the first tool in the list otherwise, then replacing the URL with what it adopted. That resolver reacts to the toolId param and to the tool list rather than to page activation, so it also re-points the URL when the list changes underneath it. The Tool House page never reads or writes ?tree=. A toolhouse/… id reaches it only by way of the redirect above, which is issued by one of the two tree pages' hosts. Reading an Id An id's first segment names the page that owns it, and therefore the folder that documents it: ?tree= root Route Documented under execution/… /execution Execution Page equipment/… /general-setup General Setup Page toolhouse/… /tool-house/… Tool House Page The remaining segments are the branch path, one segment per level of the tree, and the branch's own page sits in that folder — equipment/workpiece/material/cutting-parameter is the Cutting Parameter item of the Workpiece branch on the General Setup page. Most segments are kebab-case role names; the two list-backed branches, Mission entries and Program files, use a positional index instead. Every segment comes from the node id, never from the label the user reads: the General Setup page's root node is labelled General Setup and carries the id equipment. A label is a display string — the translation of the node's labelKey where it has one, and otherwise raw data such as an NC file name or a mission command's user-typed title, as Control Tree sets out — while an id is neither translated nor taken from data. Two consequences follow. A ?tree= link is locale-independent, and an id can never be read off what is on screen. Titles A route's meta.title holds an i18n key, such as routes.execution, not a title. The router resolves it through the active locale in an afterEach hook and sets the document title to the translated name followed by - HiNC; a route with no key — the catch-all — leaves the bare product name. The sibling name: is the route id used by every programmatic navigation and is never translated; the two must not be confused, which is why the route table above lists them side by side. The same resolver is handed to the i18n module through registerRetitle, so that switching language re-titles a parked tab without a navigation. The registration is indirect because the router already imports the i18n module for its translation function, and importing back would close a cycle. Serving These URLs History mode means the browser sends the whole path to the server on a refresh or a pasted link, so the back end maps two SPA fallbacks. The bare fallback carries an implicit constraint that rejects any URL whose last segment contains a dot, which is exactly the shape a File Explorer deep link takes, since those mirror real file names. An explicit fallback for the explorer's path is therefore mapped ahead of it with no such constraint. Static assets cannot be shadowed by either, because static-file serving runs earlier in the pipeline. Both fallbacks allow anonymous access, so the SPA itself always loads and the sign-in decision is made in the client. That decision is a navigation guard: it hydrates the authentication status once, lets every navigation through when the back end reports the feature disabled, and otherwise sends an unauthenticated visitor to the login route with the original full path — ?tree= included — parked in a redirect query. A successful sign-in replays that path as a full page load rather than a router navigation, so the application re-initialises with the cookie present. A visitor who is already signed in, or who arrives while the feature is off, is sent straight back out of the login route to the same parked path. Source Code Path See HiNC App Anatomy for git repository links. Web Application HiNC-2025-webservice (Quasar CLI SPA): wwwroot-src/src/router/routes.ts — the route table, the redirect-only records, the login route outside the shell layout, and the trailing catch-all. wwwroot-src/src/router/treeRoutes.ts — migrateLegacyTreeId, TREE_PAGE_ROOTS, routeForTreeId, the three tab-name lists it shares with the Tool House page, and SPINDLE_TABS, which only the spindle redirect reads. wwwroot-src/src/router/index.ts — the history-mode router factory, the authentication guard, and the retitle hook registered with the i18n module. wwwroot-src/src/components/controlTree/useControlTreeHost.ts — the tree-page host: rawTreePathOfRoute, treePathOfRoute, the two selection/URL watchers and the unguarded controller-checkbox watcher beside them, landingSelection, applyRouteSelection and syncUrlBack, plus the build-time reveal of a URL-named CSV or CL controller node. wwwroot-src/src/composables/useRouteTabs.ts — the tab-to-param sync the Tool House route uses, including dormant levels and the keep-alive re-entry canonicalisation. wwwroot-src/src/pages/ToolHousePage.vue — consumes the shared tab lists, resolves the tool from its path param, and navigates by route name when the tool changes. wwwroot-src/src/pages/FileExplorerPage.vue — mirrors the browsed location into the route's catch-all param and back. wwwroot-src/src/pages/MachineToolPage.vue — the component behind the URL-only machine-tool route. wwwroot-src/src/pages/NotFoundPage.vue — the catch-all component, carrying its own layout. wwwroot-src/src/pages/LoginPage.vue — reads the guard's redirect argument and replays it. wwwroot-src/src/composables/useViewPrefs.ts — the browser-local store holding the per-page last selected id and the expanded-node list that migration is applied to. wwwroot-src/src/components/AppMenuBar.vue — the menu entries that navigate by route name. wwwroot-src/src/i18n/en/routes.ts — the English strings the meta.title keys resolve to. wwwroot-src/src/i18n/index.ts — registerRetitle and the locale switch that calls it. wwwroot-src/quasar.config.ts — selects history mode and names the build output folder the server serves. Program.cs — the two SPA fallbacks, the explorer-specific one ahead of the bare one. See Also Control Tree — the tree these ids name: how a node id is formed and what a branch is made of Main Panel — the shell whose menus navigate to these routes and whose keep-alive cache makes the route-name guards necessary Execution Page — the busiest consumer of ?tree=, and the page a fall-through id lands on" + "summary": "Tree Ids and Routes The web client addresses itself with two things: a vue-router path, and — on the two Control-Tree pages — a tree query argument naming the selected tree node, as in /general-setup?tree=equipment/fixture/geometry. This page is the reference for both surfaces: the route table, the redirect-only paths that keep older bookmarks resolving, the id-migration chain, and the resolver that decides which page owns a given ?tree= id. The router runs in HTML5 history mode, so every one of these paths is a real URL the server has to answer. Important Nothing here promises that a Control-Tree id is stable. The guarantee is narrower and exact: an id keeps resolving, because every regroup adds a migration hop to migrateLegacyTreeId rather than rewriting the previous one. The ids themselves have moved repeatedly, and a page that quotes one is quoting a value that can move again. The Route Table / is the shell-layout record itself; every route below it except the login and catch-all records is one of its children, so each renders inside the Main Panel's frame and menu bar. Path Route name What it owns / — The shell layout. It carries no page of its own; its empty child redirects to the Execution route. /execution execution The run cockpit and the Execution Control Tree, whose selection rides ?tree=execution/…. /general-setup general-setup The equipment Control Tree, whose selection rides ?tree=equipment/…. /machine-tool machine-tool The machining chain on a canvas of its own, beside a left column that shows either a read-only identity panel or the chain's XML source — two states of one column, chosen with a GUI/XML toggle. A load button installs a chain file into the project. Carries no Page-menu entry and is reached by URL. /tool-house/:toolId(\\d+)?/:tab?/:subtab? tool-house The tool library and the per-tool editor. The three optional segments carry the selected tool and the two nested tab levels. /preference/log preference-log The Log Viewer, reached from the menu bar's Show Log button. It is not under /util/. /util/file-explorer/:location(.*)* util-file-explorer The File Explorer. Its catch-all mirrors the browsed location — root display name followed by the relative segments — into the path. /util/mech-builder util-mech-builder The Mechanism Builder. /login login The sign-in form. It sits outside the shell layout and carries its own Quasar layout. /:catchAll(.*)* — The 404 page, likewise outside the shell layout: it prints the unmatched full path and offers one button back to the Execution route. The menu bar's Page dropdown holds every one of these that is menu-reachable, in setup order: Tool House, General Setup and Execution, then File Explorer and Mechanism Builder below a separator. The Log Viewer has a button of its own rather than a menu entry, and /machine-tool has neither — it is reached by URL. The Tool House route's tool segment is constrained to digits, but all three of its segments are optional, so a non-numeric segment in the tool position is not rejected: the router skips the tool parameter and reads that segment as the tab, which is what makes /tool-house/cutter a working tab deep link with no tool named. The consequence is that the record absorbs three segments when the first is a number and only two when it is not, and a URL carrying more than the record can absorb — /tool-house/abc/def/ghi — falls through to the catch-all. An unrecognised tab name is not an error either: the page canonicalises it to that level's default, as The Tool House Translation sets out. Redirect-Only Paths These records carry no component. They exist so that a link minted before the corresponding editor moved into a Control Tree still lands on the editor. Path Lands on /controller/:rest(.*)* /general-setup?tree=equipment/controller — any trailing path is discarded, the retired Controller page's / segment included, so every form lands on the branch root. /spindle-capability/:tab? /general-setup?tree=equipment/spindle, with / appended when the segment is one of thermal, gear-shift, dry-run, power, torque. An unrecognised segment is dropped and the branch root is selected. /equipment/spindle /general-setup?tree=equipment/spindle /fixture/:rest(.*)* /general-setup?tree=equipment/fixture — any trailing path is discarded. /workpiece/:rest(.*)* /general-setup?tree=equipment/workpiece — any trailing path is discarded. /equipment/background-coolant /general-setup?tree=equipment/background. That id is the Environment root over the Ambient Temperature and Coolant leaves (equipment/background/environment-temperature, equipment/background/coolant); the redirect lands on the root (the ids and the route keep the legacy background spelling). /mission /execution?tree=execution/mission The five spindle tab names are declared in treeRoutes.ts as SPINDLE_TABS, and imported by wwwroot-src/src/router/routes.ts — which is the list the redirect tests its :tab? segment against. The equipment tree does not import that constant: it spells the same five segments as literals while building the equipment/spindle/ children, so redirect and branch agree by convention rather than through a shared list — renaming a spindle section is therefore an edit in two places. The Tool House name lists below are the other case, genuinely shared. The ?tree= Query Selection and URL are synced two ways by the Control-Tree host, one instance per tree page. URL to selection. A watcher on the query drives applyRouteSelection(), and it is registered immediate, so an id belonging to another page redirects on the first tick rather than after this page's first tree build. The host also calls the same function once the tree has actually been built, which is when a deep link can finally be honoured. Selection to URL. A watcher on the selected id replaces the tree argument, preserving the rest of the query. It uses router.replace, so browsing the tree does not fill the browser's history with one entry per node. The comparison that breaks the loop is made against the raw query rather than the migrated form, which is what makes an older id canonicalise: opening ?tree=controller selects the node and then rewrites the URL to ?tree=equipment/controller. Neither watcher touches the URL unless the current route name is the page's own. The shell layout keeps every visited page alive, so a host whose page is not showing keeps receiving route changes, and without the guard it would write another page's URL. The selection watcher does one thing before that guard: it records the id as this page's last selection. That ordering is load-bearing, because a selection can move while its page is off screen — unticking a CSV or CL Controller checkbox steps the equipment host off that node onto the equipment root, and the Preference menu that carries those checkboxes is open on every page — and the landing selection has to have followed it. That same checkbox flip is a third writer of the tree argument, and the one place the guard is absent. The equipment host watches both checkboxes, and when the standing selection is a node the flip removes, it replaces tree with equipment — the rest of the query preserved — before stepping the selection off. The route name is not consulted there, so the replacement goes to whichever route is showing. What applyRouteSelection Does The change is ignored unless this page owns the current route. The raw query is migrated into today's id. If its first segment names a different page and that segment is one of the known roots, the location is replaced with the route that owns it and the pass stops. An empty query falls back to the landing selection: the persisted last id for this page when that id exists in the tree just built, otherwise the page's root node — which is always present once the tree is built, so the editor column always has something to show. An id the built tree does not contain is ignored — the current selection stands and the URL keeps the unrecognised value until the next selection overwrites it. This is deliberate: the redirect in step 2 fires only for known roots, because sending an unroutable id back to the same page would loop. Otherwise every ancestor prefix of the id is added to the expanded set so the node is visible, and the selection is requested through the same gate a tree click uses. A panel holding unsaved edits may refuse the switch, and a refusal re-points the URL at the selection that actually stands. The Id the URL Names, Before the Tree Exists treePathOfRoute() — the raw query put through migrateLegacyTreeId — is not read only by the selection logic. The equipment tree consults it while it is being built, to decide whether to materialise the CSV Controller and CL Controller nodes: each is normally shown only when its Preference checkbox is ticked, and a URL naming one reveals it regardless. That reveal has to happen at build time precisely because step 4 above refuses an id the built tree lacks, so a bookmark to a switched-off node would otherwise dead-end. Only the URL reveals a node this way; the persisted last selection does not, so a node the user has just unticked while standing on it does not resurrect itself. Id Migration migrateLegacyTreeId is one pass of ordered guards over the whole id; the first that matches returns, and an id matching none is returned unchanged. An id shaped like Becomes controller, controller/… equipment/controller, equipment/controller/… spindle, spindle/… equipment/spindle, equipment/spindle/… mission, mission/… execution/mission, execution/mission/… equipment/mission, equipment/mission/… execution/mission, execution/mission/… any id ending in /contours/tray, or containing /contours/tray/ the same id with that segment spelled fluting The last rule renames one segment in place and leaves its children — baseline, flute-, side, bottom — untouched, so a deep link into a flute contour survives the engine's Fluting type naming. The two mission rules cover the two id shapes separately rather than chaining, because the first matching guard returns. The function is applied at four points, which is what makes the guarantee hold in practice: to the raw ?tree= query, on every read; to the persisted last selection, before it is looked up in the tree; to the persisted list of expanded node ids, once when a host is constructed, so an older expansion set still unfolds the branches it names; as the first step of routeForTreeId, so the id-to-page resolver never sees an unmigrated id. Note what the first rule implies: a bare ?tree=controller selects the equipment/controller branch — the controller editor on the General Setup page — and the redirect-only /controller path above lands on the same branch, so a bookmark from the retired Controller page's era resolves in either form. Landing an Id on Its Page TREE_PAGE_ROOTS lists the first segments that name a page: execution, equipment and toolhouse. spindle is absent on purpose — migration folds it into equipment/… before any root check runs, so no root check ever sees it. routeForTreeId migrates the id, then dispatches on its first segment: toolhouse — the Tool House route, with the id's segments translated into path params (below). equipment — the General Setup route, carrying the migrated id as ?tree=. anything else — the Execution route, carrying the migrated id as ?tree=. This is a fall-through, not a test for execution, so an unrecognised id handed to this function lands on the Execution page. Reaching it with a genuinely unroutable id is prevented upstream: the host calls the function only for ids whose root is in TREE_PAGE_ROOTS. The returned location replaces the whole current location. Only the tree argument survives the hop; any other query argument on the URL being redirected away from is dropped, and the Tool House form carries no query at all. The Tool House Translation The Tool House page keeps its state in path segments rather than a query, so an id arriving from another page has to be translated. routeForTreeId walks the segments of toolhouse/tool- / / : segment two contributes toolId when it is tool- followed by an integer; segment three contributes tab when it is one of general, cutter, holder, clamping, intelligent; segment four contributes subtab when it is one of the cutter sections — material, profile, contours, upper-beam, opt — or one of the holder sections, geometry and resolution. Only the sub-tab step is nested inside the tab step: an unrecognised tab discards the sub-tab with it, whereas the tool step is tested on its own, so a second segment that is not tool- costs the toolId param alone and the tab still translates. Everything deeper than the last segment the URL can carry is discarded either way — an id pointing at a single flute contour under …/cutter/contours/fluting/… lands on the nearest tab the URL can express. The same three name lists are imported by the page itself, so the tab set and the translation cannot drift apart. Once on the page, the tab segments are kept in step with the tabs by useRouteTabs, a composable whose only consumer this page is. It gives each tab level one route param, a valid-name set and a default; a nested level may declare which parent values make it apply, and while its parent is something else the level is dormant — its segment is dropped from the URL while its reference quietly remembers the last value, so returning to that parent tab returns to the sub-tab it had. The Tool House sub-tab level applies under cutter and holder only, and both its valid set and its default depend on which of the two is showing. A segment the level does not recognise resolves to that default rather than failing. Canonicalisation runs on the first mount and on every keep-alive re-entry, which is why a bare /tool-house acquires its tab segments. The tool segment is not one of the composable's levels: the page fills it in itself, adopting the URL's tool when the project holds it and the first tool in the list otherwise, then replacing the URL with what it adopted. That resolver reacts to the toolId param and to the tool list rather than to page activation, so it also re-points the URL when the list changes underneath it. The Tool House page never reads or writes ?tree=. A toolhouse/… id reaches it only by way of the redirect above, which is issued by one of the two tree pages' hosts. Reading an Id An id's first segment names the page that owns it, and therefore the folder that documents it: ?tree= root Route Documented under execution/… /execution Execution Page equipment/… /general-setup General Setup Page toolhouse/… /tool-house/… Tool House Page The remaining segments are the branch path, one segment per level of the tree, and the branch's own page sits in that folder — equipment/workpiece/material/cutting-parameter is the Cutting Parameter item of the Workpiece branch on the General Setup page. Most segments are kebab-case role names; the two list-backed branches, Mission entries and Program files, use a positional index instead. Every segment comes from the node id, never from the label the user reads: the General Setup page's root node is labelled General Setup and carries the id equipment. A label is a display string — the translation of the node's labelKey where it has one, and otherwise raw data such as an NC file name or a mission command's user-typed title, as Control Tree sets out — while an id is neither translated nor taken from data. Two consequences follow. A ?tree= link is locale-independent, and an id can never be read off what is on screen. Titles A route's meta.title holds an i18n key, such as routes.execution, not a title. The router resolves it through the active locale in an afterEach hook and sets the document title to the translated name followed by - HiNC; a route with no key — the catch-all — leaves the bare product name. The sibling name: is the route id used by every programmatic navigation and is never translated; the two must not be confused, which is why the route table above lists them side by side. The same resolver is handed to the i18n module through registerRetitle, so that switching language re-titles a parked tab without a navigation. The registration is indirect because the router already imports the i18n module for its translation function, and importing back would close a cycle. Serving These URLs History mode means the browser sends the whole path to the server on a refresh or a pasted link, so the back end maps two SPA fallbacks. The bare fallback carries an implicit constraint that rejects any URL whose last segment contains a dot, which is exactly the shape a File Explorer deep link takes, since those mirror real file names. An explicit fallback for the explorer's path is therefore mapped ahead of it with no such constraint. Static assets cannot be shadowed by either, because static-file serving runs earlier in the pipeline. Both fallbacks allow anonymous access, so the SPA itself always loads and the sign-in decision is made in the client. That decision is a navigation guard: it hydrates the authentication status once, lets every navigation through when the back end reports the feature disabled, and otherwise sends an unauthenticated visitor to the login route with the original full path — ?tree= included — parked in a redirect query. A successful sign-in replays that path as a full page load rather than a router navigation, so the application re-initialises with the cookie present. A visitor who is already signed in, or who arrives while the feature is off, is sent straight back out of the login route to the same parked path. Source Code Path See HiNC App Anatomy for git repository links. Web Application HiNC-2025-webservice (Quasar CLI SPA): wwwroot-src/src/router/routes.ts — the route table, the redirect-only records, the login route outside the shell layout, and the trailing catch-all. wwwroot-src/src/router/treeRoutes.ts — migrateLegacyTreeId, TREE_PAGE_ROOTS, routeForTreeId, the three tab-name lists it shares with the Tool House page, and SPINDLE_TABS, which only the spindle redirect reads. wwwroot-src/src/router/index.ts — the history-mode router factory, the authentication guard, and the retitle hook registered with the i18n module. wwwroot-src/src/components/controlTree/useControlTreeHost.ts — the tree-page host: rawTreePathOfRoute, treePathOfRoute, the two selection/URL watchers and the unguarded controller-checkbox watcher beside them, landingSelection, applyRouteSelection and syncUrlBack, plus the build-time reveal of a URL-named CSV or CL controller node. wwwroot-src/src/composables/useRouteTabs.ts — the tab-to-param sync the Tool House route uses, including dormant levels and the keep-alive re-entry canonicalisation. wwwroot-src/src/pages/ToolHousePage.vue — consumes the shared tab lists, resolves the tool from its path param, and navigates by route name when the tool changes. wwwroot-src/src/pages/FileExplorerPage.vue — mirrors the browsed location into the route's catch-all param and back. wwwroot-src/src/pages/MachineToolPage.vue — the component behind the URL-only machine-tool route. wwwroot-src/src/pages/NotFoundPage.vue — the catch-all component, carrying its own layout. wwwroot-src/src/pages/LoginPage.vue — reads the guard's redirect argument and replays it. wwwroot-src/src/composables/useViewPrefs.ts — the browser-local store holding the per-page last selected id and the expanded-node list that migration is applied to. wwwroot-src/src/components/AppMenuBar.vue — the menu entries that navigate by route name. wwwroot-src/src/i18n/en/routes.ts — the English strings the meta.title keys resolve to. wwwroot-src/src/i18n/index.ts — registerRetitle and the locale switch that calls it. wwwroot-src/quasar.config.ts — selects history mode and names the build output folder the server serves. Program.cs — the two SPA fallbacks, the explorer-specific one ahead of the bare one. See Also Control Tree — the tree these ids name: how a node id is formed and what a branch is made of Main Panel — the shell whose menus navigate to these routes and whose keep-alive cache makes the route-name guards necessary Execution Page — the busiest consumer of ?tree=, and the page a fall-through id lands on" }, "anatomy/shell/bottom-message-bar.html": { "href": "anatomy/shell/bottom-message-bar.html", @@ -382,7 +382,7 @@ "anatomy/shell/main-panel.html": { "href": "anatomy/shell/main-panel.html", "title": "Main Panel | HiAPI-C# 2025", - "summary": "Main Panel The Main Panel is the primary window of the HiNC application, providing navigation and access to all major features. Key Models Project Service: injects ProxyProjectService, the IProjectService implementation that reaches the session's project across the connection User Service: UserService Layout Structure Top Navigation Menu Brand logo, and the HiAPI version as an outlined badge beside it. The badge carries the HiNc assembly version reported by the anonymous authentication-status probe the router runs before the first route resolves, so it needs neither a loaded project nor a signed-in session; it is omitted only while that probe has reported no version. Project Menu Dropdown Project Path Text Field — readonly; reads “No Project Loaded” until a project is loaded New MenuItem Load MenuItem ReLoad MenuItem Save MenuItem Save As MenuItem Close Project MenuItem (below a separator) ReLoad, Save, Save As and Close Project are disabled until a project is loaded, and New, Load and Save As open the shared file-picker dialog with a .hincproj filter. The picker is allowed the Admin and Project roots and is denied the Resource root, which holds read-only templates the project endpoints cannot save through; it asks for the Admin root by name, so that is where it opens, and it seeds its path box with the directory holding the loaded project, or with the admin root itself when there is none. The Project root is one of the two only while a project is loaded: the roots endpoint lists a root only when its directory resolves, and the project directory resolves to nothing until a project is open, so with no project the picker offers Admin alone. Page Menu Dropdown — the three workflow pages in setup order (fill the tool house, set up the equipment, run), then the utilities. Tool House MenuItem Open Tool House Page General Setup MenuItem The equipment Control Tree — Machine Tool, Spindle Capability, Background, Coolant, Fixture, Workpiece, Controller, in that order — plus the shared equipment canvas. Two further controller branches, CSV Controller and CL Controller, are hidden by default and are switched on from the Preference dropdown. Execution MenuItem Open Execution Page File Explorer MenuItem (below a separator). See Util Pages. Mechanism Builder MenuItem Open Mechanism Builder Page The dropdown is not every route the application has. The Machine Tool page stays reachable by URL for its chain-only canvas preview, the Log Viewer is reached by the Show Log button, and the Fixture, Workpiece, Spindle Capability, Mission, Background / Coolant and legacy Controller paths resolve as redirects into the two tree pages. Preference Menu Dropdown Show Log Button — a button, not a menu item. It sits on the menu bar's right side and routes to the Log Viewer page. The Log Viewer presents the server's application log for the current day, with a manual refresh, a selectable auto-refresh interval, copy to the clipboard, and download of the day's log file for offline analysis. Central Page Panel — one router outlet wrapped in a keep-alive cache keyed on a project epoch: an integer the layout owns, raised by two watchers and read by nothing else. The first watches the project store's path, which New, Load and Save As each assign from the response they get back, which Close Project clears, and which a store-level watcher on the shared execution-status hub adopts from every broadcast — so a project change made in another tab, from another browser, or outside the browser altogether bumps the epoch here as well, and so does the boot status fetch, once, on a service that already has a project open. The second watches a counter the store raises in exactly one place, ReLoad, which is what makes a re-read of the same path remount at all: the backend raises its project-changed event with the path it already had, so the broadcast cannot be told apart from a no-op. Assigning the path it already holds moves neither watcher, so Save on the current path does not remount and neither does a Save As written back onto the path already open. A bump discards every cached page and rebuilds it, so each page initializes on its own mount hook rather than watching for project changes itself. Bottom footer — the routine-progress bar: the latest foreground message with a recent-messages history menu on the left, the live session status in the middle, and in-flight background job progress on the right. See Message Section on Main Panel. The menu bar carries no run tool bars at all: the transport controls and the execution status badge ride the run header the Execution Page‘s Control Tree pane pins above its tree, and the view controls ride its canvas panel header. What the menu bar keeps instead is the page's set of column quick-toggles, the connection badge, the active page's title, the Show Log button and — when authentication is on — the logout button. The toggles follow whichever tree page is current: four on the Execution page (control dock, canvas, strip charts, step info) and three on General Setup (control dock, content, canvas); the Tool House page lays itself out with plain splitters and gets none. The connection badge is Execution-only — the other pages’ canvases carry their own in-panel badges. Project Menu Behavior The Project Path Text Field displays the current project path when a project is loaded. It is implemented as a pure text field (not a button) that allows users to select and copy the path. The Project Menu manages MachiningProject with the following operations: Operation Description Example New Creates a new project See DemoBuildGeomOnlyMachiningProject Load Opens an existing project See DemoUseMachiningProject ReLoad Re-reads the current project from disk, same path — Save Saves the current project See DemoBuildGeomOnlyMachiningProject Save As Saves the project to a new location See DemoBuildGeomOnlyMachiningProject Close Closes the current project and clears the shell — Every Project action reports through two channels: a background progress line on the footer while it runs, then a toast when it lands — positive on success, a “busy” warning when a concurrent action has already claimed the service (HTTP 409), negative otherwise. What a project change drives in the shell is the layout's keep-alive epoch, not a canvas view: every cached page is discarded and rebuilt. Note Project actions report through the toast helper and the routine-progress footer store, and none of them routes a message through MessageUtil. Project I/O is asynchronous, so the shell stays responsive during file I/O. Platform-Specific Differences Web Application The Execution Page is the landing route — / redirects to /execution The page URL and panel state are synchronized (bi-directional navigation) There is no Environment dropdown. Machine Tool, Fixture, Workpiece, Controller, Background / Coolant and Spindle Capability are branches of the General Setup page's Control Tree, and Tool House and Execution are pages of their own; the remaining paths resolve as redirects into those pages. The menu bar is therefore Project ▾ | Page ▾ | Preference ▾. Source Code Path See HiNC App Anatomy for git repository links. Web Application HiNC-2025-webservice (Quasar CLI SPA): Environments/PreferenceController.cs — the endpoints behind the Preference dropdown. Environments/ProjectController.cs — the project endpoints: status, new, load, save, reload, saveas and close, plus the log endpoints. Environments/UserService.cs — the shell's user model. wwwroot-src/src/components/AppMenuBar.vue — the whole navigation menu. wwwroot-src/src/components/AppFooter.vue — the routine-progress footer the layout docks. wwwroot-src/src/layouts/MainLayout.vue — the shell that hosts the menu bar, the keep-alive page panel and the footer. wwwroot-src/src/router/routes.ts — the routes the Page dropdown targets and the redirect-only legacy paths. wwwroot-src/src/i18n/en/menu.ts — the menu bar's English labels. wwwroot-src/src/stores/project.ts — the six Project actions and the busy error a 409 becomes. wwwroot-src/src/stores/routineProgress.ts — the foreground-message and background-progress store the Project handlers share with the footer. wwwroot-src/src/composables/useToast.ts — the toasts every Project action ends in. wwwroot-src/src/composables/useViewPrefs.ts — the device-local per-page column visibility and the CSV / CL controller switches. wwwroot-src/src/composables/useConnectionsHealth.ts — the aggregate state behind the Execution connection badge. wwwroot-src/src/components/widgets/FileExplorerDialog.vue — the shared picker New, Load and Save As open. wwwroot-src/src/components/widgets/ColumnToggleIcon.vue — the glyph each column quick-toggle draws. wwwroot-src/src/pages/LogViewerPage.vue — the Log Viewer the Show Log button opens. See Also Execution Page — the landing page the shell routes to Preference Menu Dropdown — the third menu on the bar Bottom Message Bar — the notification bar the shell docks along the bottom General Setup Page — the equipment page the Page menu reaches Tree Ids and Routes — the route table this bar navigates, and how a ?tree= id lands on the page that owns it Session State — the keep-alive this shell wraps the router view in, and what a project change destroys Login and Authentication — the gate in front of this shell, and the sign-out entry on this bar Log Viewer Page — the screen the Show Log button opens" + "summary": "Main Panel The Main Panel is the primary window of the HiNC application, providing navigation and access to all major features. Key Models Project Service: injects ProxyProjectService, the IProjectService implementation that reaches the session's project across the connection User Service: UserService Layout Structure Top Navigation Menu Brand logo, and the HiAPI version as an outlined badge beside it. The badge carries the HiNc assembly version reported by the anonymous authentication-status probe the router runs before the first route resolves, so it needs neither a loaded project nor a signed-in session; it is omitted only while that probe has reported no version. Project Menu Dropdown Project Path Text Field — readonly; reads “No Project Loaded” until a project is loaded New MenuItem Load MenuItem ReLoad MenuItem Save MenuItem Save As MenuItem Close Project MenuItem (below a separator) ReLoad, Save, Save As and Close Project are disabled until a project is loaded, and New, Load and Save As open the shared file-picker dialog with a .hincproj filter. The picker is allowed the Admin and Project roots and is denied the Resource root, which holds read-only templates the project endpoints cannot save through; it asks for the Admin root by name, so that is where it opens, and it seeds its path box with the directory holding the loaded project, or with the admin root itself when there is none. The Project root is one of the two only while a project is loaded: the roots endpoint lists a root only when its directory resolves, and the project directory resolves to nothing until a project is open, so with no project the picker offers Admin alone. Page Menu Dropdown — the three workflow pages in setup order (fill the tool house, set up the equipment, run), then the utilities. Tool House MenuItem Open Tool House Page General Setup MenuItem The equipment Control Tree — four roots: Mechanism (Machine Tool / Fixture / Workpiece), Spindle Capability, Environment (Ambient Temperature / Coolant) and Controller, in that order — plus the shared equipment canvas. Two further controller branches, CSV Controller and CL Controller, are hidden by default and are switched on from the Preference dropdown. Execution MenuItem Open Execution Page File Explorer MenuItem (below a separator). See Util Pages. Mechanism Builder MenuItem Open Mechanism Builder Page The dropdown is not every route the application has. The Machine Tool page stays reachable by URL for its chain-only canvas preview, the Log Viewer is reached by the Show Log button, and the Fixture, Workpiece, Spindle Capability, Mission, Environment (Ambient Temperature / Coolant) and legacy Controller paths resolve as redirects into the two tree pages. Preference Menu Dropdown Show Log Button — a button, not a menu item. It sits on the menu bar's right side and routes to the Log Viewer page. The Log Viewer presents the server's application log for the current day, with a manual refresh, a selectable auto-refresh interval, copy to the clipboard, and download of the day's log file for offline analysis. Central Page Panel — one router outlet wrapped in a keep-alive cache keyed on a project epoch: an integer the layout owns, raised by two watchers and read by nothing else. The first watches the project store's path, which New, Load and Save As each assign from the response they get back, which Close Project clears, and which a store-level watcher on the shared execution-status hub adopts from every broadcast — so a project change made in another tab, from another browser, or outside the browser altogether bumps the epoch here as well, and so does the boot status fetch, once, on a service that already has a project open. The second watches a counter the store raises in exactly one place, ReLoad, which is what makes a re-read of the same path remount at all: the backend raises its project-changed event with the path it already had, so the broadcast cannot be told apart from a no-op. Assigning the path it already holds moves neither watcher, so Save on the current path does not remount and neither does a Save As written back onto the path already open. A bump discards every cached page and rebuilds it, so each page initializes on its own mount hook rather than watching for project changes itself. Bottom footer — the routine-progress bar: the latest foreground message with a recent-messages history menu on the left, the live session status in the middle, and in-flight background job progress on the right. See Message Section on Main Panel. The menu bar carries no run tool bars at all: the transport controls and the execution status badge ride the run header the Execution Page‘s Control Tree pane pins above its tree, and the view controls ride its canvas panel header. What the menu bar keeps instead is the page's set of column quick-toggles, the connection badge, the active page's title, the Show Log button and — when authentication is on — the logout button. The toggles follow whichever tree page is current: four on the Execution page (control dock, canvas, strip charts, step info) and three on General Setup (control dock, content, canvas); the Tool House page lays itself out with plain splitters and gets none. The connection badge is Execution-only — the other pages’ canvases carry their own in-panel badges. Project Menu Behavior The Project Path Text Field displays the current project path when a project is loaded. It is implemented as a pure text field (not a button) that allows users to select and copy the path. The Project Menu manages MachiningProject with the following operations: Operation Description Example New Creates a new project See DemoBuildGeomOnlyMachiningProject Load Opens an existing project See DemoUseMachiningProject ReLoad Re-reads the current project from disk, same path — Save Saves the current project See DemoBuildGeomOnlyMachiningProject Save As Saves the project to a new location See DemoBuildGeomOnlyMachiningProject Close Closes the current project and clears the shell — Every Project action reports through two channels: a background progress line on the footer while it runs, then a toast when it lands — positive on success, a “busy” warning when a concurrent action has already claimed the service (HTTP 409), negative otherwise. What a project change drives in the shell is the layout's keep-alive epoch, not a canvas view: every cached page is discarded and rebuilt. Note Project actions report through the toast helper and the routine-progress footer store, and none of them routes a message through MessageUtil. Project I/O is asynchronous, so the shell stays responsive during file I/O. Platform-Specific Differences Web Application The Execution Page is the landing route — / redirects to /execution The page URL and panel state are synchronized (bi-directional navigation) There is no Environment dropdown (Environment is now a root of the General Setup page's Control Tree, over Ambient Temperature / Coolant). Mechanism (Machine Tool / Fixture / Workpiece), Spindle Capability, Environment and Controller are the roots of that tree, and Tool House and Execution are pages of their own; the remaining paths resolve as redirects into those pages. The menu bar is therefore Project ▾ | Page ▾ | Preference ▾. Source Code Path See HiNC App Anatomy for git repository links. Web Application HiNC-2025-webservice (Quasar CLI SPA): Environments/PreferenceController.cs — the endpoints behind the Preference dropdown. Environments/ProjectController.cs — the project endpoints: status, new, load, save, reload, saveas and close, plus the log endpoints. Environments/UserService.cs — the shell's user model. wwwroot-src/src/components/AppMenuBar.vue — the whole navigation menu. wwwroot-src/src/components/AppFooter.vue — the routine-progress footer the layout docks. wwwroot-src/src/layouts/MainLayout.vue — the shell that hosts the menu bar, the keep-alive page panel and the footer. wwwroot-src/src/router/routes.ts — the routes the Page dropdown targets and the redirect-only legacy paths. wwwroot-src/src/i18n/en/menu.ts — the menu bar's English labels. wwwroot-src/src/stores/project.ts — the six Project actions and the busy error a 409 becomes. wwwroot-src/src/stores/routineProgress.ts — the foreground-message and background-progress store the Project handlers share with the footer. wwwroot-src/src/composables/useToast.ts — the toasts every Project action ends in. wwwroot-src/src/composables/useViewPrefs.ts — the device-local per-page column visibility and the CSV / CL controller switches. wwwroot-src/src/composables/useConnectionsHealth.ts — the aggregate state behind the Execution connection badge. wwwroot-src/src/components/widgets/FileExplorerDialog.vue — the shared picker New, Load and Save As open. wwwroot-src/src/components/widgets/ColumnToggleIcon.vue — the glyph each column quick-toggle draws. wwwroot-src/src/pages/LogViewerPage.vue — the Log Viewer the Show Log button opens. See Also Execution Page — the landing page the shell routes to Preference Menu Dropdown — the third menu on the bar Bottom Message Bar — the notification bar the shell docks along the bottom General Setup Page — the equipment page the Page menu reaches Tree Ids and Routes — the route table this bar navigates, and how a ?tree= id lands on the page that owns it Session State — the keep-alive this shell wraps the router view in, and what a project change destroys Login and Authentication — the gate in front of this shell, and the sign-out entry on this bar Log Viewer Page — the screen the Show Log button opens" }, "anatomy/shell/preference-menu.html": { "href": "anatomy/shell/preference-menu.html", @@ -2447,7 +2447,7 @@ "api/Hi.Machining.MachiningEquipmentUtils.MachiningEquipment.html": { "href": "api/Hi.Machining.MachiningEquipmentUtils.MachiningEquipment.html", "title": "Class MachiningEquipment | HiAPI-C# 2025", - "summary": "Class MachiningEquipment Namespace Hi.Machining.MachiningEquipmentUtils Assembly HiMech.dll The runtime (execution) face of the machining equipment: the topology instance the runner drives — tool-change graph surgery, collision detection, live axis poses. Materialised from the authored face (MaterialiseMachiningEquipment(string, IProgress )) and NEVER serialized: runtime data cannot reach the project file by construction. public class MachiningEquipment : IMachiningEquipment, IDisplayee, IExpandToBox3d, IGetAnchoredDisplayeeList, IGetProgramCl, IGetAsmb, IGetAnchor, IGetTopoIndex, IGetMachiningChain, IGetMachiningEquipment Inheritance object MachiningEquipment Implements IMachiningEquipment IDisplayee IExpandToBox3d IGetAnchoredDisplayeeList IGetProgramCl IGetAsmb IGetAnchor IGetTopoIndex IGetMachiningChain IGetMachiningEquipment Inherited Members object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.MemberwiseClone() object.ReferenceEquals(object, object) object.ToString() Extension Methods DispUtil.Display(IDisplayee, Bind, Mat4d) MachiningEquipmentUtil.AlignWorkpieceProgramZeroToIso(IMachiningEquipment, Vec3d) MachiningEquipmentUtil.GetIsoCoordinatePosition(IMachiningEquipment, Vec3d) MachiningEquipmentUtil.GetMachinePositionAtProgramZero(IMachiningEquipment) MachiningEquipmentUtil.GetMachinePositionAtTableBuckleZero(IMachiningEquipment) MachiningEquipmentUtil.GetProgramToPnMat4d(IMachiningEquipment) DuplicateUtil.TryDuplicate (TSelf, params object[]) InvokeUtil.SelfInvoke (TSrc, Action ) InvokeUtil.SelfInvoke (TSrc, Func ) TopoUtil.Display(IGetAnchor, Bind, Dictionary ) TopoUtil.ExpandToBox3d(IGetAnchor, Box3d, Dictionary ) ColorUtil.GetGloomyColor(object, double, double) NameUtil.GetSelectionName(object) StringUtil.GetPropertyStringIfToStringNotOverloaded(object, bool, bool) LockUtil.Lock(object) Constructors MachiningEquipment() Ctor. public MachiningEquipment() Properties Asmb Asmb of the entire equipment. public Asmb Asmb { get; } Property Value Asmb BackgroundTemperature_C Gets or sets the background temperature in Celsius. This is a convenience property that converts between Celsius and Kelvin. public double BackgroundTemperature_C { get; set; } Property Value double BackgroundTemperature_K Gets or sets the background temperature in Kelvin. Runtime-stamped from the authored face at materialise; the authored value's home is BackgroundTemperature_K. public double BackgroundTemperature_K { get; set; } Property Value double CoolantHeatCondition Gets or sets the coolant heat condition settings. Runtime-stamped from the authored face at materialise (shared reference — the runtime only reads it); the authored home is CoolantHeatCondition. public CoolantHeatCondition CoolantHeatCondition { get; set; } Property Value CoolantHeatCondition Fixture Fixture. public Fixture Fixture { get; set; } Property Value Fixture MachiningChain Body of the equipment. public IMachiningChain MachiningChain { get; set; } Property Value IMachiningChain MachiningTool Milling tool. public IMachiningTool MachiningTool { get; set; } Property Value IMachiningTool SpindleCapability Gets or sets the spindle capability configuration. Runtime-stamped from the authored face at materialise (shared reference — the runtime only reads it); the authored home is SpindleCapability. public SpindleCapability SpindleCapability { get; set; } Property Value SpindleCapability TableToComp Transformer of the branch from table buckle to workpiece side buckle. Note that the workpiece side buckle links to Fixture if fixture exist; otherwise, it links to Workpiece if workpiece exist. If Workpiece either Fixture do not exist, this property makes no effect. public ITransformer TableToComp { get; set; } Property Value ITransformer Workpiece Workpiece. public Workpiece Workpiece { get; set; } Property Value Workpiece WorkpieceDisplayee Displayee for workpiece rendering. Set by the runtime service layer. public IDisplayee WorkpieceDisplayee { get; set; } Property Value IDisplayee Methods Detect(bool) Performs collision detection. public MechCollisionResult Detect(bool addFluteAndWorkpieceDetection) Parameters addFluteAndWorkpieceDetection bool Whether to include flute and workpiece in detection. Returns MechCollisionResult Significant collision result. Display(Bind) Display function called in DispEngine rendering loop. public void Display(Bind bind) Parameters bind Bind Bind with DispEngine. See Bind. ExpandToBox3d(Box3d) Expands the destination box. This function is usually used to compute the bounding box of elements. public void ExpandToBox3d(Box3d dst) Parameters dst Box3d Destination box GetAnchor() Get key anchor. (i.e. root anchor) public Anchor GetAnchor() Returns Anchor key anchor GetAnchoredDisplayeeList() Gets a list of anchored displayable objects. public List GetAnchoredDisplayeeList() Returns List A list of IAnchoredDisplayee objects GetAsmb() Gets the key asmb. public Asmb GetAsmb() Returns Asmb The key asmb. GetMachiningChain() Gets the machining chain instance. public IMachiningChain GetMachiningChain() Returns IMachiningChain The machining chain instance. GetMachiningEquipment() Get the runtime MachiningEquipment. public MachiningEquipment GetMachiningEquipment() Returns MachiningEquipment MachiningEquipment GetProgramCl() Get CL (Cutter Location). Where Point is tool tip position; Normal is tool orientation. public DVec3d GetProgramCl() Returns DVec3d CL GetToolTipXyzOnProgramZero() Get tool tip xyz from workpiece geom anchor. public Vec3d GetToolTipXyzOnProgramZero() Returns Vec3d if no MachiningTool or no Workpiece equiping, return null; otherwise, return the XYZ from workpiece geomanchor to tool tip. GetTransformFromRootToProgramZero() Gets the transform matrix from the root coordinate system to the program zero coordinate system. public Mat4d GetTransformFromRootToProgramZero() Returns Mat4d A 4x4 transformation matrix representing the coordinate system transformation. IsCollisionRed(object) Whether the latest Detect(bool) pass flagged item as colliding. Display paths use this through CollisionRedScope to paint the part red. public bool IsCollisionRed(object item) Parameters item object A displayed item (typically a Solid). Returns bool true if the item is currently collision-red. PrepareCollidableItems() Prepares all collidable items for collision detection. This method should be called before performing collision detection. public void PrepareCollidableItems() ResetCollisionFlags() Resets all collision flags to their default states. This should be called after collision detection is complete, and by a runtime reset so no part stays painted red. public void ResetCollisionFlags() Tooling(int, MachiningToolHouse) Set MachiningTool by toolId and toolHouse. public bool Tooling(int toolId, MachiningToolHouse toolHouse) Parameters toolId int tool ID toolHouse MachiningToolHouse tool house Returns bool true if tool changed; otherwise, false. Exceptions ToolNotFoundException Throw If toolId does not exist on toolHouse." + "summary": "Class MachiningEquipment Namespace Hi.Machining.MachiningEquipmentUtils Assembly HiMech.dll The runtime (execution) face of the machining equipment: the topology instance the runner drives — tool-change graph surgery, collision detection, live axis poses. Materialised from the authored face (MaterialiseMachiningEquipment(string, IProgress )) and NEVER serialized: runtime data cannot reach the project file by construction. public class MachiningEquipment : IMachiningEquipment, IDisplayee, IExpandToBox3d, IGetAnchoredDisplayeeList, IGetProgramCl, IGetAsmb, IGetAnchor, IGetTopoIndex, IGetMachiningChain, IGetMachiningEquipment Inheritance object MachiningEquipment Implements IMachiningEquipment IDisplayee IExpandToBox3d IGetAnchoredDisplayeeList IGetProgramCl IGetAsmb IGetAnchor IGetTopoIndex IGetMachiningChain IGetMachiningEquipment Inherited Members object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.MemberwiseClone() object.ReferenceEquals(object, object) object.ToString() Extension Methods DispUtil.Display(IDisplayee, Bind, Mat4d) MachiningEquipmentUtil.AlignWorkpieceProgramZeroToIso(IMachiningEquipment, Vec3d) MachiningEquipmentUtil.GetIsoCoordinatePosition(IMachiningEquipment, Vec3d) MachiningEquipmentUtil.GetMachinePositionAtProgramZero(IMachiningEquipment) MachiningEquipmentUtil.GetMachinePositionAtTableBuckleZero(IMachiningEquipment) MachiningEquipmentUtil.GetProgramToPnMat4d(IMachiningEquipment) DuplicateUtil.TryDuplicate (TSelf, params object[]) InvokeUtil.SelfInvoke (TSrc, Action ) InvokeUtil.SelfInvoke (TSrc, Func ) TopoUtil.Display(IGetAnchor, Bind, Dictionary ) TopoUtil.ExpandToBox3d(IGetAnchor, Box3d, Dictionary ) ColorUtil.GetGloomyColor(object, double, double) NameUtil.GetSelectionName(object) StringUtil.GetPropertyStringIfToStringNotOverloaded(object, bool, bool) LockUtil.Lock(object) Constructors MachiningEquipment() Ctor. public MachiningEquipment() Properties AmbientTemperature_C Gets or sets the ambient temperature in Celsius. This is a convenience property that converts between Celsius and Kelvin. public double AmbientTemperature_C { get; set; } Property Value double AmbientTemperature_K Gets or sets the ambient temperature in Kelvin. Runtime-stamped from the authored face at materialise; the authored value's home is AmbientTemperature_K. public double AmbientTemperature_K { get; set; } Property Value double Asmb Asmb of the entire equipment. public Asmb Asmb { get; } Property Value Asmb BackgroundTemperature_C Source-compatible delegate of AmbientTemperature_C. [Obsolete(\"Renamed to AmbientTemperature_C.\")] public double BackgroundTemperature_C { get; set; } Property Value double BackgroundTemperature_K Source-compatible delegate of AmbientTemperature_K. [Obsolete(\"Renamed to AmbientTemperature_K.\")] public double BackgroundTemperature_K { get; set; } Property Value double CoolantHeatCondition Gets or sets the coolant heat condition settings. Runtime-stamped from the authored face at materialise (shared reference — the runtime only reads it); the authored home is CoolantHeatCondition. public CoolantHeatCondition CoolantHeatCondition { get; set; } Property Value CoolantHeatCondition Fixture Fixture. public Fixture Fixture { get; set; } Property Value Fixture MachiningChain Body of the equipment. public IMachiningChain MachiningChain { get; set; } Property Value IMachiningChain MachiningTool Milling tool. public IMachiningTool MachiningTool { get; set; } Property Value IMachiningTool SpindleCapability Gets or sets the spindle capability configuration. Runtime-stamped from the authored face at materialise (shared reference — the runtime only reads it); the authored home is SpindleCapability. public SpindleCapability SpindleCapability { get; set; } Property Value SpindleCapability TableToComp Transformer of the branch from table buckle to workpiece side buckle. Note that the workpiece side buckle links to Fixture if fixture exist; otherwise, it links to Workpiece if workpiece exist. If Workpiece either Fixture do not exist, this property makes no effect. public ITransformer TableToComp { get; set; } Property Value ITransformer Workpiece Workpiece. public Workpiece Workpiece { get; set; } Property Value Workpiece WorkpieceDisplayee Displayee for workpiece rendering. Set by the runtime service layer. public IDisplayee WorkpieceDisplayee { get; set; } Property Value IDisplayee Methods Detect(bool) Performs collision detection. public MechCollisionResult Detect(bool addFluteAndWorkpieceDetection) Parameters addFluteAndWorkpieceDetection bool Whether to include flute and workpiece in detection. Returns MechCollisionResult Significant collision result. Display(Bind) Display function called in DispEngine rendering loop. public void Display(Bind bind) Parameters bind Bind Bind with DispEngine. See Bind. ExpandToBox3d(Box3d) Expands the destination box. This function is usually used to compute the bounding box of elements. public void ExpandToBox3d(Box3d dst) Parameters dst Box3d Destination box GetAnchor() Get key anchor. (i.e. root anchor) public Anchor GetAnchor() Returns Anchor key anchor GetAnchoredDisplayeeList() Gets a list of anchored displayable objects. public List GetAnchoredDisplayeeList() Returns List A list of IAnchoredDisplayee objects GetAsmb() Gets the key asmb. public Asmb GetAsmb() Returns Asmb The key asmb. GetMachiningChain() Gets the machining chain instance. public IMachiningChain GetMachiningChain() Returns IMachiningChain The machining chain instance. GetMachiningEquipment() Get the runtime MachiningEquipment. public MachiningEquipment GetMachiningEquipment() Returns MachiningEquipment MachiningEquipment GetProgramCl() Get CL (Cutter Location). Where Point is tool tip position; Normal is tool orientation. public DVec3d GetProgramCl() Returns DVec3d CL GetToolTipXyzOnProgramZero() Get tool tip xyz from workpiece geom anchor. public Vec3d GetToolTipXyzOnProgramZero() Returns Vec3d if no MachiningTool or no Workpiece equiping, return null; otherwise, return the XYZ from workpiece geomanchor to tool tip. GetTransformFromRootToProgramZero() Gets the transform matrix from the root coordinate system to the program zero coordinate system. public Mat4d GetTransformFromRootToProgramZero() Returns Mat4d A 4x4 transformation matrix representing the coordinate system transformation. IsCollisionRed(object) Whether the latest Detect(bool) pass flagged item as colliding. Display paths use this through CollisionRedScope to paint the part red. public bool IsCollisionRed(object item) Parameters item object A displayed item (typically a Solid). Returns bool true if the item is currently collision-red. PrepareCollidableItems() Prepares all collidable items for collision detection. This method should be called before performing collision detection. public void PrepareCollidableItems() ResetCollisionFlags() Resets all collision flags to their default states. This should be called after collision detection is complete, and by a runtime reset so no part stays painted red. public void ResetCollisionFlags() Tooling(int, MachiningToolHouse) Set MachiningTool by toolId and toolHouse. public bool Tooling(int toolId, MachiningToolHouse toolHouse) Parameters toolId int tool ID toolHouse MachiningToolHouse tool house Returns bool true if tool changed; otherwise, false. Exceptions ToolNotFoundException Throw If toolId does not exist on toolHouse." }, "api/Hi.Machining.MachiningEquipmentUtils.MachiningEquipmentCollisionIndex.html": { "href": "api/Hi.Machining.MachiningEquipmentUtils.MachiningEquipmentCollisionIndex.html", @@ -2467,7 +2467,7 @@ "api/Hi.Machining.MachiningEquipmentUtils.SetupEquipment.html": { "href": "api/Hi.Machining.MachiningEquipmentUtils.SetupEquipment.html", "title": "Class SetupEquipment | HiAPI-C# 2025", - "summary": "Class SetupEquipment Namespace Hi.Machining.MachiningEquipmentUtils Assembly HiMech.dll The authored (setup) face of the machining equipment: the machine chain, workpiece, fixture, environment data and the Setup-page tool selection, with the project XML IO. This is the ONLY face that persists — the runtime face (MachiningEquipment) is materialised from it and never serialized, so a mid-run save can no longer write live poses or the runner-equipped tool into the project file. The XML wire name stays \"MachiningEquipment\" (see XName): shipped project files keep their layout, only the deserialized object changed. public class SetupEquipment : IMachiningEquipment, IDisplayee, IExpandToBox3d, IGetAnchoredDisplayeeList, IGetProgramCl, IGetAsmb, IGetAnchor, IGetTopoIndex, IGetMachiningChain, IMakeXmlSource Inheritance object SetupEquipment Implements IMachiningEquipment IDisplayee IExpandToBox3d IGetAnchoredDisplayeeList IGetProgramCl IGetAsmb IGetAnchor IGetTopoIndex IGetMachiningChain IMakeXmlSource Inherited Members object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.MemberwiseClone() object.ReferenceEquals(object, object) object.ToString() Extension Methods DispUtil.Display(IDisplayee, Bind, Mat4d) MachiningEquipmentUtil.AlignWorkpieceProgramZeroToIso(IMachiningEquipment, Vec3d) MachiningEquipmentUtil.GetIsoCoordinatePosition(IMachiningEquipment, Vec3d) MachiningEquipmentUtil.GetMachinePositionAtProgramZero(IMachiningEquipment) MachiningEquipmentUtil.GetMachinePositionAtTableBuckleZero(IMachiningEquipment) MachiningEquipmentUtil.GetProgramToPnMat4d(IMachiningEquipment) DuplicateUtil.TryDuplicate (TSelf, params object[]) InvokeUtil.SelfInvoke (TSrc, Action ) InvokeUtil.SelfInvoke (TSrc, Func ) TopoUtil.Display(IGetAnchor, Bind, Dictionary ) TopoUtil.ExpandToBox3d(IGetAnchor, Box3d, Dictionary ) ColorUtil.GetGloomyColor(object, double, double) NameUtil.GetSelectionName(object) StringUtil.GetPropertyStringIfToStringNotOverloaded(object, bool, bool) LockUtil.Lock(object) Constructors SetupEquipment() Ctor. public SetupEquipment() SetupEquipment(XElement, string, string, IProgress ) Initializes a new instance of the SetupEquipment class from XML data. public SetupEquipment(XElement src, string baseDirectory, string relFile, IProgress progress) Parameters src XElement The XML element containing the equipment configuration. baseDirectory string The base directory for resolving relative file paths. relFile string The relative file path for XML serialization. progress IProgress Progress reporter for diagnostic messages emitted during construction. Properties Asmb Asmb of the entire authored equipment topology. public Asmb Asmb { get; } Property Value Asmb BackgroundTemperature_C Gets or sets the background temperature in Celsius. This is a convenience property that converts between Celsius and Kelvin. public double BackgroundTemperature_C { get; set; } Property Value double BackgroundTemperature_K Gets or sets the background temperature in Kelvin. This represents the ambient temperature of the machining environment. public double BackgroundTemperature_K { get; set; } Property Value double CoolantHeatCondition Gets or sets the coolant heat condition settings. This includes coolant temperature and heat transfer coefficients. public CoolantHeatCondition CoolantHeatCondition { get; set; } Property Value CoolantHeatCondition CoolantHeatConditionFile Gets or sets the file path of the coolant heat condition (WorkpieceMaterial pattern: when set, XML IO externalizes CoolantHeatCondition to this side-file; when null the condition serializes inline). public string CoolantHeatConditionFile { get; set; } Property Value string Fixture Fixture. public Fixture Fixture { get; set; } Property Value Fixture MachiningChain Body of the equipment — the authored machine topology instance. The runtime face gets its own instance from MaterialiseMachiningEquipment(string, IProgress ); the two never share graph objects (only leaf Solid geometry is shared). public IMachiningChain MachiningChain { get; set; } Property Value IMachiningChain MachiningChainFile Gets or sets the file path of the solid machining chain. This is used for XML serialization and file management. public string MachiningChainFile { get; set; } Property Value string MachiningTool The Setup-page selected tool (persisted as the project's ). Never the tool-house instance itself — see Tooling(int, MachiningToolHouse). public IMachiningTool MachiningTool { get; set; } Property Value IMachiningTool SpindleCapability Gets or sets the spindle capability configuration. This defines the operational capabilities and limits of the spindle. public SpindleCapability SpindleCapability { get; set; } Property Value SpindleCapability SpindleCapabilityFile Gets or sets the file path of the spindle capability configuration. This is used for XML serialization and file management. public string SpindleCapabilityFile { get; set; } Property Value string TableToComp Transformer of the branch from table buckle to workpiece side buckle. Note that the workpiece side buckle links to Fixture if fixture exist; otherwise, it links to Workpiece if workpiece exist. If Workpiece either Fixture do not exist, this property makes no effect. public ITransformer TableToComp { get; set; } Property Value ITransformer Workpiece Workpiece. public Workpiece Workpiece { get; set; } Property Value Workpiece WorkpieceDisplayee Displayee for workpiece rendering. Optional on the authored face — setup views typically draw the workpiece through their own display composition instead. public IDisplayee WorkpieceDisplayee { get; set; } Property Value IDisplayee XName Name for XML IO. Pinned to the shipped wire name “MachiningEquipment” — the type was split off the runtime face, the file layout was not. public static string XName { get; } Property Value string Methods Display(Bind) Display function called in DispEngine rendering loop. public void Display(Bind bind) Parameters bind Bind Bind with DispEngine. See Bind. ExpandToBox3d(Box3d) Expands the destination box. This function is usually used to compute the bounding box of elements. public void ExpandToBox3d(Box3d dst) Parameters dst Box3d Destination box GetAnchor() Get key anchor. (i.e. root anchor) public Anchor GetAnchor() Returns Anchor key anchor GetAnchoredDisplayeeList() Gets a list of anchored displayable objects. public List GetAnchoredDisplayeeList() Returns List A list of IAnchoredDisplayee objects GetAsmb() Gets the key asmb. public Asmb GetAsmb() Returns Asmb The key asmb. GetMachiningChain() Gets the machining chain instance. public IMachiningChain GetMachiningChain() Returns IMachiningChain The machining chain instance. GetProgramCl() Get CL (Cutter Location). Where Point is tool tip position; Normal is tool orientation. public DVec3d GetProgramCl() Returns DVec3d CL GetToolTipXyzOnProgramZero() Get tool tip xyz from workpiece geom anchor. public Vec3d GetToolTipXyzOnProgramZero() Returns Vec3d if no MachiningTool or no Workpiece equiping, return null; otherwise, return the XYZ from workpiece geomanchor to tool tip. GetTransformFromRootToProgramZero() Gets the transform matrix from the root coordinate system to the program zero coordinate system. public Mat4d GetTransformFromRootToProgramZero() Returns Mat4d A 4x4 transformation matrix representing the coordinate system transformation. MakeXmlSource(string, string, bool) Creates an XML representation of the object. This method may also generate additional resources such as related files. public XElement MakeXmlSource(string baseDirectory, string relFile, bool exhibitionOnly) Parameters baseDirectory string The base directory for resolving relative paths relFile string The relative file path for the XML source exhibitionOnly bool if true, the extended file creation is suppressed. Returns XElement An XML element representing the object's state Remarks For the demand of easy moving source folder (especially project folder) without configuration file path corruption, the relative file path is applied. The baseDirectory is typically the folder at the nearest configuration file folder. Since the folder can be moving with the configuration file. MaterialiseMachiningEquipment(string, IProgress ) Builds the runtime face from this authored face: a fresh MachiningEquipment whose topology is an XML round-trip copy of this one (chain, fixture, workpiece, table transformer, tool), with the heavy machine-body and fixture Solid instances SHARED (this face keeps their lifecycle), axis poses copied, and the environment data stamped by reference. Information flows one way: the returned instance never writes back into this one. public MachiningEquipment MaterialiseMachiningEquipment(string baseDirectory, IProgress progress) Parameters baseDirectory string The project base directory this equipment's relative paths (e.g. MachiningChainFile) resolve against. progress IProgress Progress reporter for diagnostics during the copy. Returns MachiningEquipment The materialised runtime equipment. Reg(XFactory) Registers this type's deserializer with the given XFactory and chains Reg(factory) on dependents. Idempotent. public static void Reg(XFactory factory = null) Parameters factory XFactory Tooling(int, MachiningToolHouse) Selects the Setup-page tool by toolId from toolHouse. The authored face never hosts the tool-house instance itself: the runtime face equips house instances (and mutates their tessellation mid-run), and one tool's Asmb cannot live in two topologies — so this hosts a private duplicate. Clear the selection (“do not show”) by setting MachiningTool to null. public bool Tooling(int toolId, MachiningToolHouse toolHouse) Parameters toolId int tool ID toolHouse MachiningToolHouse tool house Returns bool true if the selection changed; otherwise, false. Exceptions ToolNotFoundException Throw If toolId does not exist on toolHouse." + "summary": "Class SetupEquipment Namespace Hi.Machining.MachiningEquipmentUtils Assembly HiMech.dll The authored (setup) face of the machining equipment: the machine chain, workpiece, fixture, environment data and the Setup-page tool selection, with the project XML IO. This is the ONLY face that persists — the runtime face (MachiningEquipment) is materialised from it and never serialized, so a mid-run save can no longer write live poses or the runner-equipped tool into the project file. The XML wire name stays \"MachiningEquipment\" (see XName): shipped project files keep their layout, only the deserialized object changed. public class SetupEquipment : IMachiningEquipment, IDisplayee, IExpandToBox3d, IGetAnchoredDisplayeeList, IGetProgramCl, IGetAsmb, IGetAnchor, IGetTopoIndex, IGetMachiningChain, IMakeXmlSource Inheritance object SetupEquipment Implements IMachiningEquipment IDisplayee IExpandToBox3d IGetAnchoredDisplayeeList IGetProgramCl IGetAsmb IGetAnchor IGetTopoIndex IGetMachiningChain IMakeXmlSource Inherited Members object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.MemberwiseClone() object.ReferenceEquals(object, object) object.ToString() Extension Methods DispUtil.Display(IDisplayee, Bind, Mat4d) MachiningEquipmentUtil.AlignWorkpieceProgramZeroToIso(IMachiningEquipment, Vec3d) MachiningEquipmentUtil.GetIsoCoordinatePosition(IMachiningEquipment, Vec3d) MachiningEquipmentUtil.GetMachinePositionAtProgramZero(IMachiningEquipment) MachiningEquipmentUtil.GetMachinePositionAtTableBuckleZero(IMachiningEquipment) MachiningEquipmentUtil.GetProgramToPnMat4d(IMachiningEquipment) DuplicateUtil.TryDuplicate (TSelf, params object[]) InvokeUtil.SelfInvoke (TSrc, Action ) InvokeUtil.SelfInvoke (TSrc, Func ) TopoUtil.Display(IGetAnchor, Bind, Dictionary ) TopoUtil.ExpandToBox3d(IGetAnchor, Box3d, Dictionary ) ColorUtil.GetGloomyColor(object, double, double) NameUtil.GetSelectionName(object) StringUtil.GetPropertyStringIfToStringNotOverloaded(object, bool, bool) LockUtil.Lock(object) Constructors SetupEquipment() Ctor. public SetupEquipment() SetupEquipment(XElement, string, string, IProgress ) Initializes a new instance of the SetupEquipment class from XML data. public SetupEquipment(XElement src, string baseDirectory, string relFile, IProgress progress) Parameters src XElement The XML element containing the equipment configuration. baseDirectory string The base directory for resolving relative file paths. relFile string The relative file path for XML serialization. progress IProgress Progress reporter for diagnostic messages emitted during construction. Properties AmbientTemperature_C Gets or sets the ambient temperature in Celsius. This is a convenience property that converts between Celsius and Kelvin. public double AmbientTemperature_C { get; set; } Property Value double AmbientTemperature_K Gets or sets the ambient temperature in Kelvin: the shop-floor temperature the workpiece, cutter, chips and spindle start at and the spindle cools toward. The cutting zone itself convects to CoolantTemperature_K. Serialized as AmbientTemperature_C; the pre-rename element BackgroundTemperature_C is still read. public double AmbientTemperature_K { get; set; } Property Value double Asmb Asmb of the entire authored equipment topology. public Asmb Asmb { get; } Property Value Asmb BackgroundTemperature_C Source-compatible delegate of AmbientTemperature_C. [Obsolete(\"Renamed to AmbientTemperature_C.\")] public double BackgroundTemperature_C { get; set; } Property Value double BackgroundTemperature_K Source-compatible delegate of AmbientTemperature_K. [Obsolete(\"Renamed to AmbientTemperature_K.\")] public double BackgroundTemperature_K { get; set; } Property Value double CoolantHeatCondition Gets or sets the coolant heat condition settings. This includes coolant temperature and heat transfer coefficients. public CoolantHeatCondition CoolantHeatCondition { get; set; } Property Value CoolantHeatCondition CoolantHeatConditionFile Gets or sets the file path of the coolant heat condition (WorkpieceMaterial pattern: when set, XML IO externalizes CoolantHeatCondition to this side-file; when null the condition serializes inline). public string CoolantHeatConditionFile { get; set; } Property Value string Fixture Fixture. public Fixture Fixture { get; set; } Property Value Fixture MachiningChain Body of the equipment — the authored machine topology instance. The runtime face gets its own instance from MaterialiseMachiningEquipment(string, IProgress ); the two never share graph objects (only leaf Solid geometry is shared). public IMachiningChain MachiningChain { get; set; } Property Value IMachiningChain MachiningChainFile Gets or sets the file path of the solid machining chain. This is used for XML serialization and file management. public string MachiningChainFile { get; set; } Property Value string MachiningTool The Setup-page selected tool (persisted as the project's ). Never the tool-house instance itself — see Tooling(int, MachiningToolHouse). public IMachiningTool MachiningTool { get; set; } Property Value IMachiningTool SpindleCapability Gets or sets the spindle capability configuration. This defines the operational capabilities and limits of the spindle. public SpindleCapability SpindleCapability { get; set; } Property Value SpindleCapability SpindleCapabilityFile Gets or sets the file path of the spindle capability configuration. This is used for XML serialization and file management. public string SpindleCapabilityFile { get; set; } Property Value string TableToComp Transformer of the branch from table buckle to workpiece side buckle. Note that the workpiece side buckle links to Fixture if fixture exist; otherwise, it links to Workpiece if workpiece exist. If Workpiece either Fixture do not exist, this property makes no effect. public ITransformer TableToComp { get; set; } Property Value ITransformer Workpiece Workpiece. public Workpiece Workpiece { get; set; } Property Value Workpiece WorkpieceDisplayee Displayee for workpiece rendering. Optional on the authored face — setup views typically draw the workpiece through their own display composition instead. public IDisplayee WorkpieceDisplayee { get; set; } Property Value IDisplayee XName Name for XML IO. Pinned to the shipped wire name “MachiningEquipment” — the type was split off the runtime face, the file layout was not. public static string XName { get; } Property Value string Methods Display(Bind) Display function called in DispEngine rendering loop. public void Display(Bind bind) Parameters bind Bind Bind with DispEngine. See Bind. ExpandToBox3d(Box3d) Expands the destination box. This function is usually used to compute the bounding box of elements. public void ExpandToBox3d(Box3d dst) Parameters dst Box3d Destination box GetAnchor() Get key anchor. (i.e. root anchor) public Anchor GetAnchor() Returns Anchor key anchor GetAnchoredDisplayeeList() Gets a list of anchored displayable objects. public List GetAnchoredDisplayeeList() Returns List A list of IAnchoredDisplayee objects GetAsmb() Gets the key asmb. public Asmb GetAsmb() Returns Asmb The key asmb. GetMachiningChain() Gets the machining chain instance. public IMachiningChain GetMachiningChain() Returns IMachiningChain The machining chain instance. GetProgramCl() Get CL (Cutter Location). Where Point is tool tip position; Normal is tool orientation. public DVec3d GetProgramCl() Returns DVec3d CL GetToolTipXyzOnProgramZero() Get tool tip xyz from workpiece geom anchor. public Vec3d GetToolTipXyzOnProgramZero() Returns Vec3d if no MachiningTool or no Workpiece equiping, return null; otherwise, return the XYZ from workpiece geomanchor to tool tip. GetTransformFromRootToProgramZero() Gets the transform matrix from the root coordinate system to the program zero coordinate system. public Mat4d GetTransformFromRootToProgramZero() Returns Mat4d A 4x4 transformation matrix representing the coordinate system transformation. MakeXmlSource(string, string, bool) Creates an XML representation of the object. This method may also generate additional resources such as related files. public XElement MakeXmlSource(string baseDirectory, string relFile, bool exhibitionOnly) Parameters baseDirectory string The base directory for resolving relative paths relFile string The relative file path for the XML source exhibitionOnly bool if true, the extended file creation is suppressed. Returns XElement An XML element representing the object's state Remarks For the demand of easy moving source folder (especially project folder) without configuration file path corruption, the relative file path is applied. The baseDirectory is typically the folder at the nearest configuration file folder. Since the folder can be moving with the configuration file. MaterialiseMachiningEquipment(string, IProgress ) Builds the runtime face from this authored face: a fresh MachiningEquipment whose topology is an XML round-trip copy of this one (chain, fixture, workpiece, table transformer, tool), with the heavy machine-body and fixture Solid instances SHARED (this face keeps their lifecycle), axis poses copied, and the environment data stamped by reference. Information flows one way: the returned instance never writes back into this one. public MachiningEquipment MaterialiseMachiningEquipment(string baseDirectory, IProgress progress) Parameters baseDirectory string The project base directory this equipment's relative paths (e.g. MachiningChainFile) resolve against. progress IProgress Progress reporter for diagnostics during the copy. Returns MachiningEquipment The materialised runtime equipment. Reg(XFactory) Registers this type's deserializer with the given XFactory and chains Reg(factory) on dependents. Idempotent. public static void Reg(XFactory factory = null) Parameters factory XFactory Tooling(int, MachiningToolHouse) Selects the Setup-page tool by toolId from toolHouse. The authored face never hosts the tool-house instance itself: the runtime face equips house instances (and mutates their tessellation mid-run), and one tool's Asmb cannot live in two topologies — so this hosts a private duplicate. Clear the selection (“do not show”) by setting MachiningTool to null. public bool Tooling(int toolId, MachiningToolHouse toolHouse) Parameters toolId int tool ID toolHouse MachiningToolHouse tool house Returns bool true if the selection changed; otherwise, false. Exceptions ToolNotFoundException Throw If toolId does not exist on toolHouse." }, "api/Hi.Machining.MachiningEquipmentUtils.html": { "href": "api/Hi.Machining.MachiningEquipmentUtils.html", @@ -2482,7 +2482,7 @@ "api/Hi.Machining.MachiningVolumeRemovalProc.StepMotionSnapshot.html": { "href": "api/Hi.Machining.MachiningVolumeRemovalProc.StepMotionSnapshot.html", "title": "Class MachiningVolumeRemovalProc.StepMotionSnapshot | HiAPI-C# 2025", - "summary": "Class MachiningVolumeRemovalProc.StepMotionSnapshot Namespace Hi.Machining Assembly HiMech.dll Represents a snapshot of the machining motion state. public record MachiningVolumeRemovalProc.StepMotionSnapshot : IEquatable Inheritance object MachiningVolumeRemovalProc.StepMotionSnapshot Implements IEquatable Inherited Members object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.MemberwiseClone() object.ReferenceEquals(object, object) object.ToString() Extension Methods DuplicateUtil.TryDuplicate (TSelf, params object[]) InvokeUtil.SelfInvoke (TSrc, Action ) InvokeUtil.SelfInvoke (TSrc, Func ) ColorUtil.GetGloomyColor(object, double, double) NameUtil.GetSelectionName(object) StringUtil.GetPropertyStringIfToStringNotOverloaded(object, bool, bool) LockUtil.Lock(object) Constructors StepMotionSnapshot(DVec3d, DVec3d, SeqPair , Dictionary , double[], bool, IMachiningTool, WorkpieceService, double, CoolantHeatCondition, SortedList , DVec3d) Represents a snapshot of the machining motion state. public StepMotionSnapshot(DVec3d GeomCl, DVec3d ProgramCl, SeqPair Seq, Dictionary AnchorTransformDictionary, double[] McValues, bool EnableSweeping, IMachiningTool MachiningTool, WorkpieceService WorkpieceService, double BackgroundTemperature_K, CoolantHeatCondition CoolantHeatCondition, SortedList FluteZToDzList, DVec3d PreTipPose = null) Parameters GeomCl DVec3d The geometric CL point. ProgramCl DVec3d The program CL point. Seq SeqPair The sequence pair of transformation matrices. AnchorTransformDictionary Dictionary Dictionary mapping anchors to their transformation matrices. McValues double[] Array of machine values. EnableSweeping bool Whether sweeping is enabled. MachiningTool IMachiningTool The machining tool being used. WorkpieceService WorkpieceService Service that owns the workpiece being machined. BackgroundTemperature_K double Background temperature in Kelvin. CoolantHeatCondition CoolantHeatCondition The coolant heat condition. FluteZToDzList SortedList Sorted list mapping flute Z positions to their deltas. PreTipPose DVec3d The tip pose the previous StepMotion(bool, double, Mat4d) call fed to the valve, on the workpiece-geometry coordinate – whether or not that call produced a step (the valve skips a collinear return over a segment it already covered). Null on the first call after a reset. The one-step reference for the real tip feedrate; Seq.pre is not, it may span two steps back. Properties AnchorTransformDictionary Dictionary mapping anchors to their transformation matrices. public Dictionary AnchorTransformDictionary { get; init; } Property Value Dictionary BackgroundTemperature_K Background temperature in Kelvin. public double BackgroundTemperature_K { get; init; } Property Value double CoolantHeatCondition The coolant heat condition. public CoolantHeatCondition CoolantHeatCondition { get; init; } Property Value CoolantHeatCondition EnableSweeping Whether sweeping is enabled. public bool EnableSweeping { get; init; } Property Value bool FluteZToDzList Sorted list mapping flute Z positions to their deltas. public SortedList FluteZToDzList { get; init; } Property Value SortedList GeomCl The geometric CL point. public DVec3d GeomCl { get; init; } Property Value DVec3d MachiningTool The machining tool being used. public IMachiningTool MachiningTool { get; init; } Property Value IMachiningTool McValues Array of machine values. public double[] McValues { get; init; } Property Value double[] PreTipPose The tip pose the previous StepMotion(bool, double, Mat4d) call fed to the valve, on the workpiece-geometry coordinate – whether or not that call produced a step (the valve skips a collinear return over a segment it already covered). Null on the first call after a reset. The one-step reference for the real tip feedrate; Seq.pre is not, it may span two steps back. public DVec3d PreTipPose { get; init; } Property Value DVec3d ProgramCl The program CL point. public DVec3d ProgramCl { get; init; } Property Value DVec3d Seq The sequence pair of transformation matrices. public SeqPair Seq { get; init; } Property Value SeqPair Workpiece The workpiece data model. public Workpiece Workpiece { get; } Property Value Workpiece WorkpieceService Service that owns the workpiece being machined. public WorkpieceService WorkpieceService { get; init; } Property Value WorkpieceService" + "summary": "Class MachiningVolumeRemovalProc.StepMotionSnapshot Namespace Hi.Machining Assembly HiMech.dll Represents a snapshot of the machining motion state. public record MachiningVolumeRemovalProc.StepMotionSnapshot : IEquatable Inheritance object MachiningVolumeRemovalProc.StepMotionSnapshot Implements IEquatable Inherited Members object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.MemberwiseClone() object.ReferenceEquals(object, object) object.ToString() Extension Methods DuplicateUtil.TryDuplicate (TSelf, params object[]) InvokeUtil.SelfInvoke (TSrc, Action ) InvokeUtil.SelfInvoke (TSrc, Func ) ColorUtil.GetGloomyColor(object, double, double) NameUtil.GetSelectionName(object) StringUtil.GetPropertyStringIfToStringNotOverloaded(object, bool, bool) LockUtil.Lock(object) Constructors StepMotionSnapshot(DVec3d, DVec3d, SeqPair , Dictionary , double[], bool, IMachiningTool, WorkpieceService, double, CoolantHeatCondition, SortedList , DVec3d) Represents a snapshot of the machining motion state. public StepMotionSnapshot(DVec3d GeomCl, DVec3d ProgramCl, SeqPair Seq, Dictionary AnchorTransformDictionary, double[] McValues, bool EnableSweeping, IMachiningTool MachiningTool, WorkpieceService WorkpieceService, double AmbientTemperature_K, CoolantHeatCondition CoolantHeatCondition, SortedList FluteZToDzList, DVec3d PreTipPose = null) Parameters GeomCl DVec3d The geometric CL point. ProgramCl DVec3d The program CL point. Seq SeqPair The sequence pair of transformation matrices. AnchorTransformDictionary Dictionary Dictionary mapping anchors to their transformation matrices. McValues double[] Array of machine values. EnableSweeping bool Whether sweeping is enabled. MachiningTool IMachiningTool The machining tool being used. WorkpieceService WorkpieceService Service that owns the workpiece being machined. AmbientTemperature_K double Ambient temperature in Kelvin. CoolantHeatCondition CoolantHeatCondition The coolant heat condition. FluteZToDzList SortedList Sorted list mapping flute Z positions to their deltas. PreTipPose DVec3d The tip pose the previous StepMotion(bool, double, Mat4d) call fed to the valve, on the workpiece-geometry coordinate – whether or not that call produced a step (the valve skips a collinear return over a segment it already covered). Null on the first call after a reset. The one-step reference for the real tip feedrate; Seq.pre is not, it may span two steps back. Properties AmbientTemperature_K Ambient temperature in Kelvin. public double AmbientTemperature_K { get; init; } Property Value double AnchorTransformDictionary Dictionary mapping anchors to their transformation matrices. public Dictionary AnchorTransformDictionary { get; init; } Property Value Dictionary CoolantHeatCondition The coolant heat condition. public CoolantHeatCondition CoolantHeatCondition { get; init; } Property Value CoolantHeatCondition EnableSweeping Whether sweeping is enabled. public bool EnableSweeping { get; init; } Property Value bool FluteZToDzList Sorted list mapping flute Z positions to their deltas. public SortedList FluteZToDzList { get; init; } Property Value SortedList GeomCl The geometric CL point. public DVec3d GeomCl { get; init; } Property Value DVec3d MachiningTool The machining tool being used. public IMachiningTool MachiningTool { get; init; } Property Value IMachiningTool McValues Array of machine values. public double[] McValues { get; init; } Property Value double[] PreTipPose The tip pose the previous StepMotion(bool, double, Mat4d) call fed to the valve, on the workpiece-geometry coordinate – whether or not that call produced a step (the valve skips a collinear return over a segment it already covered). Null on the first call after a reset. The one-step reference for the real tip feedrate; Seq.pre is not, it may span two steps back. public DVec3d PreTipPose { get; init; } Property Value DVec3d ProgramCl The program CL point. public DVec3d ProgramCl { get; init; } Property Value DVec3d Seq The sequence pair of transformation matrices. public SeqPair Seq { get; init; } Property Value SeqPair Workpiece The workpiece data model. public Workpiece Workpiece { get; } Property Value Workpiece WorkpieceService Service that owns the workpiece being machined. public WorkpieceService WorkpieceService { get; init; } Property Value WorkpieceService" }, "api/Hi.Machining.MachiningVolumeRemovalProc.html": { "href": "api/Hi.Machining.MachiningVolumeRemovalProc.html", @@ -2562,7 +2562,7 @@ "api/Hi.MachiningProcs.LocalProjectService.html": { "href": "api/Hi.MachiningProcs.LocalProjectService.html", "title": "Class LocalProjectService | HiAPI-C# 2025", - "summary": "Class LocalProjectService Namespace Hi.MachiningProcs Assembly HiNc.dll Root(Local) project service. Apply absolute file path. public class LocalProjectService : IProjectService, IMachiningProjectGetter, IMachiningService, IGetMachiningEquipment, IStepPropertyAccessHost, IDisposable Inheritance object LocalProjectService Implements IProjectService IMachiningProjectGetter IMachiningService IGetMachiningEquipment IStepPropertyAccessHost IDisposable Inherited Members object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.MemberwiseClone() object.ReferenceEquals(object, object) object.ToString() Extension Methods DuplicateUtil.TryDuplicate (TSelf, params object[]) InvokeUtil.SelfInvoke (TSrc, Action ) InvokeUtil.SelfInvoke (TSrc, Func ) ColorUtil.GetGloomyColor(object, double, double) NameUtil.GetSelectionName(object) StringUtil.GetPropertyStringIfToStringNotOverloaded(object, bool, bool) LockUtil.Lock(object) Remarks LocalProjectService handles the runtime data and cache generally not requires configuration IO. Compare to MachiningProject, LocalProjectService also handles events that does not reset on the MachiningProject been reloaded. Constructors LocalProjectService(ILogger ) Ctor. public LocalProjectService(ILogger logger = null) Parameters logger ILogger Optional logger instance. Properties ActiveNcRunner Gets the active NC runner based on EnableSoftNcRunner. public INcRunner ActiveNcRunner { get; } Property Value INcRunner BaseDirectory Gets the project base directory (relative-path root). public string BaseDirectory { get; } Property Value string BoundSelectorHost Gets the bound selector host for managing selection boundaries. public BoundSelectorHost BoundSelectorHost { get; } Property Value BoundSelectorHost ClRunner Gets the NX-CL (CLSF) runner of the project (NxClRunner); null when there is no project. public INcRunner ClRunner { get; } Property Value INcRunner ClStrip Gets the cutter location strip containing the machining steps. public ClStrip ClStrip { get; } Property Value ClStrip CsvRunner Gets the CSV runner — the CSV suit's pipeline (GeneralCsvRunner); null when there is no project. public INcRunner CsvRunner { get; } Property Value INcRunner DictionaryColorGuide Gets the color guide for dictionary-based coloring. public DictionaryColorGuide DictionaryColorGuide { get; } Property Value DictionaryColorGuide EnablePauseOnFailure Gets or sets whether to pause execution on failure. public bool EnablePauseOnFailure { get; set; } Property Value bool EnableSoftNcRunner Switches between SoftNcRunner and the legacy HardNcRunner. Default true (2026-07-17): SoftNcRunner is the flagship NC pipeline; set false to fall back to HardNcRunner for the features that still depend on it (e.g. Hi.NcOpt.NcOptProc optimization reads NcLines). Will be removed when HardNcRunner is fully replaced. public bool EnableSoftNcRunner { get; set; } Property Value bool EnableStrokeLimitCheck Gets or sets whether stroke limit checking is enabled. public bool EnableStrokeLimitCheck { get; set; } Property Value bool Fixture Gets or sets the authored fixture (setup face). The runtime face follows by rebuild; runtime readers use MachiningEquipment.Fixture. public Fixture Fixture { get; set; } Property Value Fixture Global global variable for SessionShell. Not save on XML. public Dictionary
See Also
0, 1,
the dotted 0.2 of a nested list entry); in the Tool House branch it is the tool id as a string.
Waves whose panels read a module-level state singleton rather than an indexed object leave it
-empty — the SoftNc controller leaves, the spindle sections, the Background and Coolant leaves and
+empty — the SoftNc controller leaves, the spindle sections, the Environment root's Ambient Temperature and Coolant leaves and
the Program branch all do.
/equipment/background-coolant/general-setup?tree=equipment/background. Background and Coolant are two separate tree nodes; the redirect picks Background./general-setup?tree=equipment/background. That id is the Environment root over the Ambient Temperature and Coolant leaves (equipment/background/environment-temperature, equipment/background/coolant); the redirect lands on the root (the ids and the route keep the legacy background spelling)./missionThe dropdown is not every route the application has. The Machine Tool page stays reachable by URL for its chain-only canvas preview, the Log Viewer is reached by the Show Log button, and the Fixture, Workpiece, Spindle Capability, Mission, Background / Coolant and legacy Controller paths resolve as redirects into the two tree pages.
The dropdown is not every route the application has. The Machine Tool page stays reachable by URL for its chain-only canvas preview, the Log Viewer is reached by the Show Log button, and the Fixture, Workpiece, Spindle Capability, Mission, Environment (Ambient Temperature / Coolant) and legacy Controller paths resolve as redirects into the two tree pages.
Source Code Path
See HiNC App Anatomy for git repository links.
diff --git a/App/wwwroot/HiAPI-docsite/api/Hi.Machining.MachiningEquipmentUtils.MachiningEquipment.html b/App/wwwroot/HiAPI-docsite/api/Hi.Machining.MachiningEquipmentUtils.MachiningEquipment.html index 3ea9f977..5b81137d 100644 --- a/App/wwwroot/HiAPI-docsite/api/Hi.Machining.MachiningEquipmentUtils.MachiningEquipment.html +++ b/App/wwwroot/HiAPI-docsite/api/Hi.Machining.MachiningEquipmentUtils.MachiningEquipment.html @@ -252,6 +252,73 @@ serialized: runtime data cannot reach the project file by construction. + + ++ AmbientTemperature_C + +
+ +Gets or sets the ambient temperature in Celsius. +This is a convenience property that converts between Celsius and Kelvin.
+public double AmbientTemperature_C { get; set; }
+ Property Value
+-
+
+ AmbientTemperature_K + +
+ +Gets or sets the ambient temperature in Kelvin. Runtime-stamped +from the authored face at materialise; the authored value's home is +AmbientTemperature_K.
+public double AmbientTemperature_K { get; set; }
+ Property Value
+-
+
@@ -291,13 +358,13 @@ serialized: runtime data cannot reach the project file by construction.
-Gets or sets the background temperature in Celsius. -This is a convenience property that converts between Celsius and Kelvin.
+Source-compatible delegate of AmbientTemperature_C.
public double BackgroundTemperature_C { get; set; }
+ [Obsolete("Renamed to AmbientTemperature_C.")]
+public double BackgroundTemperature_C { get; set; }
Gets or sets the background temperature in Kelvin. Runtime-stamped -from the authored face at materialise; the authored value's home is -BackgroundTemperature_K.
+Source-compatible delegate of AmbientTemperature_K.
public double BackgroundTemperature_K { get; set; }
+ [Obsolete("Renamed to AmbientTemperature_K.")]
+public double BackgroundTemperature_K { get; set; }
+ AmbientTemperature_C + +
+ +Gets or sets the ambient temperature in Celsius. +This is a convenience property that converts between Celsius and Kelvin.
+public double AmbientTemperature_C { get; set; }
+ Property Value
+-
+
+ AmbientTemperature_K + +
+ +Gets or sets the ambient temperature in Kelvin: the shop-floor
+temperature the workpiece, cutter, chips and spindle start at and the
+spindle cools toward. The cutting zone itself convects to
+CoolantTemperature_K.
+Serialized as AmbientTemperature_C; the pre-rename element
+BackgroundTemperature_C is still read.
public double AmbientTemperature_K { get; set; }
+ Property Value
+-
+
@@ -338,13 +408,13 @@ shipped project files keep their layout, only the deserialized object changed.
-Gets or sets the background temperature in Celsius. -This is a convenience property that converts between Celsius and Kelvin.
+Source-compatible delegate of AmbientTemperature_C.
public double BackgroundTemperature_C { get; set; }
+ [Obsolete("Renamed to AmbientTemperature_C.")]
+public double BackgroundTemperature_C { get; set; }
Gets or sets the background temperature in Kelvin. -This represents the ambient temperature of the machining environment.
+Source-compatible delegate of AmbientTemperature_K.
public double BackgroundTemperature_K { get; set; }
+ [Obsolete("Renamed to AmbientTemperature_K.")]
+public double BackgroundTemperature_K { get; set; }
public StepMotionSnapshot(DVec3d GeomCl, DVec3d ProgramCl, SeqPair<Mat4d> Seq, Dictionary<Anchor, Mat4d> AnchorTransformDictionary, double[] McValues, bool EnableSweeping, IMachiningTool MachiningTool, WorkpieceService WorkpieceService, double BackgroundTemperature_K, CoolantHeatCondition CoolantHeatCondition, SortedList<double, double> FluteZToDzList, DVec3d PreTipPose = null)
+ public StepMotionSnapshot(DVec3d GeomCl, DVec3d ProgramCl, SeqPair<Mat4d> Seq, Dictionary<Anchor, Mat4d> AnchorTransformDictionary, double[] McValues, bool EnableSweeping, IMachiningTool MachiningTool, WorkpieceService WorkpieceService, double AmbientTemperature_K, CoolantHeatCondition CoolantHeatCondition, SortedList<double, double> FluteZToDzList, DVec3d PreTipPose = null)