# LinuxCNC WASM Porting Steps ## Goal Build a separate WASM-based CNC simulation program that: - uses LinuxCNC source as the semantic source of truth, - does not modify the original `linuxcnc/` source tree, - is managed independently from native LinuxCNC, - provides HTML + JavaScript frontend plus OPFS persistence, - matches LinuxCNC software behavior as closely as practical except for realtime hardware driving. ## Non-Negotiable Constraints 1. `linuxcnc/` is upstream and read-only for the port effort. 2. Any source adaptation needed for WASM happens on copied or generated files under `wasm-port/`. 3. No direct edits inside `linuxcnc/src`, `linuxcnc/lib`, `linuxcnc/tests`, or `linuxcnc/web` are part of the port workflow. 4. LinuxCNC GUI code is reference-only. The migrated UI is rebuilt in HTML + JavaScript. 5. LinuxCNC compute logic should be reused before any reimplementation is considered. ## Workspace Structure Create and keep these directories under `wasm-port/`: - `docs/` Planning, architecture, and validation documents. - `vendor/linuxcnc/` Copied source files selected for the port. - `patches/` Patch files against the vendored copies. - `tools/` Scripts that extract files from `../linuxcnc`, apply patches, and verify drift. - `runtime/core/` WASM-targeted C/C++ code and wrappers. - `runtime/sdk/` JavaScript/TypeScript wrapper over the WASM module. - `runtime/ui/` HTML + JavaScript frontend. - `runtime/opfs/` Browser file adapter. - `tests/native/` Native extracted-core regression tests. - `tests/browser/` Browser/WASM regression and smoke tests. ## Ported Program Directory Structure The migrated program itself should be managed as a standalone product under `wasm-port/`, with LinuxCNC acting as an upstream source provider. The recommended final structure is: ```text wasm-port/ ├── docs/ ├── vendor/ │ └── linuxcnc/ │ └── src/ │ ├── emc/ │ │ ├── ini/ │ │ ├── kinematics/ │ │ ├── rs274ngc/ │ │ └── tp/ │ ├── hal/ │ │ └── components/ │ └── libnml/ │ └── posemath/ ├── patches/ ├── tools/ ├── runtime/ │ ├── core/ │ │ ├── include/ │ │ ├── shims/ │ │ ├── adapters/ │ │ ├── canon/ │ │ ├── session/ │ │ ├── simulation/ │ │ ├── linuxcnc_wrap/ │ │ └── c_api/ │ ├── sdk/ │ │ └── src/ │ ├── ui/ │ │ ├── public/ │ │ └── src/ │ │ ├── panels/ │ │ ├── preview/ │ │ ├── state/ │ │ ├── machine/ │ │ └── files/ │ └── opfs/ ├── tests/ │ ├── native/ │ ├── wasm/ │ └── fixtures/ ├── build/ │ ├── native/ │ └── wasm/ └── dist/ ├── sdk/ └── web/ ``` ### Directory Responsibilities - `vendor/linuxcnc/` Holds extracted upstream LinuxCNC source files. These are copied or generated from `../linuxcnc` and are the only place where source-level port patches are applied. - `patches/` Stores every patch applied to vendored LinuxCNC files. Patches are tracked here instead of being mixed into the original source tree. - `tools/` Holds extraction, sync, verification, manifest generation, and compatibility-check scripts. - `runtime/core/` The standalone simulation runtime. This is where vendored LinuxCNC source is wrapped, adapted, and exposed to the rest of the ported program. - `runtime/core/include/` Public internal headers for the standalone runtime. - `runtime/core/shims/` Small compatibility headers and implementation stubs required to compile vendored LinuxCNC code outside the native runtime. - `runtime/core/adapters/` Host boundary adapters such as file IO, logging, simulation HAL, and runtime-state providers. - `runtime/core/canon/` Canonical motion event collection and serialization. - `runtime/core/session/` Per-simulation session ownership for interpreter state, planner state, machine state, and controller state. - `runtime/core/simulation/` Higher-level simulation orchestration built on top of reused LinuxCNC compute modules. - `runtime/core/linuxcnc_wrap/` Thin wrappers around vendored LinuxCNC entry points. Prefer wrappers here over editing vendored source directly. - `runtime/core/c_api/` Stable C ABI exported to the WASM layer. - `runtime/sdk/` JavaScript/TypeScript SDK that calls the WASM module and hides memory management and ABI details from the frontend. - `runtime/ui/` The actual CNC simulation web application built with HTML + JavaScript. - `runtime/ui/src/panels/` Operator panels, machine configuration panels, parameter editors, and controller-status panels. - `runtime/ui/src/preview/` 2D/3D path preview, 5-axis visualization, joint/world overlays, and playback views. - `runtime/ui/src/state/` Browser-side state management for session lifecycle and UI coordination. - `runtime/ui/src/machine/` Machine-model-specific UI logic. - `runtime/ui/src/files/` File import/export and project/session handling UI logic. - `runtime/opfs/` OPFS-backed file services, snapshot persistence, and path mapping. - `tests/native/` Native extracted-core regression tests run before WASM build validation. - `tests/wasm/` WASM tests for Node and browser environments. - `tests/fixtures/` Shared INI, G-code, parameter, tool-table, and machine fixtures. - `build/` Intermediate build output. This is disposable. - `dist/` Deliverable artifacts such as generated web bundles and SDK packages. ### Source Ownership Rule The ported program's own source code is expected to live under: - `runtime/core/` - `runtime/sdk/` - `runtime/ui/` - `runtime/opfs/` - `tests/` - `tools/` - `docs/` Vendored LinuxCNC code must live under: - `vendor/linuxcnc/` The original upstream tree must remain outside the ported program's source ownership boundary: - `../linuxcnc/` ### Patch Placement Rule If a LinuxCNC source file needs adaptation: 1. extract it into `vendor/linuxcnc/`; 2. patch the vendored copy only; 3. record the patch in `patches/`; 4. document why the patch exists in `docs/` or in the patch header. Do not place LinuxCNC source patches under `runtime/`. ### Build Graph Rule The standalone build should flow like this: 1. `tools/` extracts upstream files into `vendor/` 2. `patches/` are applied to vendored copies 3. `runtime/core/` compiles vendored files plus wrappers 4. `runtime/sdk/` consumes the generated WASM module 5. `runtime/ui/` consumes the SDK 6. `runtime/opfs/` provides browser persistence services 7. `tests/` validate native and browser behavior This ensures the ported program remains independently buildable while still tracking LinuxCNC as the semantic source of truth. ## Phase 0: Freeze Upstream Reference Purpose: Make the LinuxCNC source baseline explicit before extraction starts. Steps: 1. Record the exact upstream commit from `linuxcnc/.git`. 2. Record local build assumptions: - compiler version - emscripten version - python version - node version 3. Record the first supported LinuxCNC fixture set: - one 3-axis machine - one non-trivial kinematics case - one 5-axis machine 4. Record the first G-code feature set: - linear motion - arc motion - canned cycles - offsets and coordinate systems - subroutines - numeric and named variables - representative 5-axis programs Outputs: - upstream revision note - supported feature baseline - supported machine baseline ## Phase 1: Build the Source Reuse Map Purpose: Identify exactly which LinuxCNC source files are needed. Steps: 1. Map each required capability to LinuxCNC files: - G-code interpreter: `../linuxcnc/src/emc/rs274ngc/*` - parameter tables and named variables: `../linuxcnc/src/emc/rs274ngc/interp_*` - INI parsing: `../linuxcnc/src/emc/ini/inifile.*` - planner: `../linuxcnc/src/emc/tp/*` - kinematics: `../linuxcnc/src/emc/kinematics/*` and selected files from `../linuxcnc/src/hal/components/*.comp` - posemath: `../linuxcnc/src/libnml/posemath/*` 2. For each file, classify it: - copy unchanged - copy plus shim - copy plus light patch - not included in phase 1 3. For each file, record dependencies: - HAL - RTAPI - NML - native file IO - Python - GUI 4. Save the mapping as a table under `wasm-port/docs/`. Outputs: - file-level reuse matrix - dependency matrix ## Phase 2: Build the Extraction Pipeline Purpose: Keep LinuxCNC source untouched while making port-specific copies available. Steps: 1. Write extraction scripts in `wasm-port/tools/`. 2. Copy selected upstream files into `wasm-port/vendor/linuxcnc/`. 3. Preserve relative structure where useful, for example: - `vendor/linuxcnc/src/emc/rs274ngc/...` - `vendor/linuxcnc/src/emc/ini/...` 4. Store every modification as: - a patch in `wasm-port/patches/`, or - a thin wrapper outside the vendored file 5. Add a verification script that compares upstream file hashes against the vendored source list. Rules: - if upstream changes, re-run extraction; - reapply patches only in the standalone workspace; - never patch `../linuxcnc` directly. Outputs: - reproducible extraction pipeline - vendored source tree ## Phase 3: Build the Native Extracted Core Purpose: Prove the reusable LinuxCNC compute code works outside the full runtime. Steps: 1. Create `wasm-port/runtime/core/` as the portable core layer. 2. Add wrapper translation units instead of editing vendored files where possible. 3. Start with these subsystems in order: - INI parser - numeric parameter table - named parameter logic - interpreter core - planner - kinematics 4. Build a native CLI harness first, before any WASM build. 5. Replace host edges with abstractions: - file provider - HAL adapter - runtime state provider - logging adapter Outputs: - portable native core - native harness executable Current verified progress: - `tools/build_native_probes.sh` builds the INI parser probe, interpreter state probe, named-parameter harness, RS274 compile probe, and the minimal interpreter harness from the standalone `wasm-port/` workspace. - `tests/native/verify_native_probes.sh` validates that all native probe exit codes are zero and that the minimal interpreter harness emits a `STRAIGHT_TRAVERSE` canonical event for `G0 X1.0 Y2.0`, plus `SET_FEED_RATE` and `STRAIGHT_FEED` canonical events for `G1 X3.0 Y4.0 F120.0`. - The same validation is now fixture-driven through `tests/fixtures/gcode/minimal_linear.ngc` and `tests/fixtures/canon/minimal_linear.events`. - `tests/fixtures/gcode/modal_incremental.ngc` and `tests/fixtures/canon/modal_incremental.events` add `G90`/`G91` distance-mode switching plus modal `G1` carry-forward coverage. The temporary wrapper behavior is based on LinuxCNC `interp_convert.cc::convert_distance_mode()` and `interp_convert.cc::convert_straight()`. - `tests/fixtures/gcode/position_params.ngc` and `tests/fixtures/canon/position_params.events` cover Z-axis motion plus current-position parameter visibility for `#5420`, `#5421`, and `#5422`. The parameter source basis is LinuxCNC `interp_parameter_def.hh` and `interp_namedparams.cc`. - `tests/fixtures/gcode/canned_cycles.ngc` and `tests/fixtures/canon/canned_cycles.events` cover LinuxCNC canned-cycle conversion through vendored `interp_cycles.cc`, including `G81`, `G82`, `G83`, `G80` cancellation, dwell, peck drilling, and incremental `L` repeats. - `runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp` now records coordinate-system canonical boundary calls emitted by vendored LinuxCNC conversion code: `SET_G5X_OFFSET`, `SET_G92_OFFSET`, `SET_XY_ROTATION`, `CANON_UPDATE_END_POINT`, `USE_LENGTH_UNITS`, and `SELECT_PLANE`. `tests/fixtures/gcode/coordinate_offsets.ngc` and `tests/fixtures/canon/coordinate_offsets.events` pin `G55`, active `G10 L2`, `G92`, `G92.1`, and `G54` behavior from `interp_convert.cc::convert_coordinate_system()`, `interp_convert.cc::convert_setup()`, and `interp_convert.cc::convert_axis_offsets()`. - `runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp` now records feed/control canonical boundary calls emitted by vendored LinuxCNC conversion and queue code: `SET_TRAVERSE_RATE`, `SET_FEED_REFERENCE`, `SET_FEED_MODE`, `SET_MOTION_CONTROL_MODE`, and `SET_NAIVECAM_TOLERANCE`. `tests/fixtures/gcode/feed_control_modes.ngc` and `tests/fixtures/canon/feed_control_modes.events` pin `G93`, `G94`, `G95`, `G61`, `G61.1`, and `G64 P/Q` behavior from `interp_convert.cc::convert_feed_mode()`, `interp_convert.cc::convert_control_mode()`, and `interp_queue.cc`. - `runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp` now records probe canonical boundary calls emitted by vendored `interp_convert.cc::convert_probe()`: `TURN_PROBE_ON`, `STRAIGHT_PROBE`, and `TURN_PROBE_OFF`. `tests/fixtures/gcode/probe_semantics.ngc` and `tests/fixtures/canon/probe_semantics.events` pin `G38.2`, `G38.3`, `G38.4`, and `G38.5` probe type handling. - `runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp` now records speed/feed synchronization and rigid-tap canonical boundary calls emitted by vendored `interp_convert.cc::convert_straight()`: `START_SPEED_FEED_SYNCH`, `STOP_SPEED_FEED_SYNCH`, and `RIGID_TAP`. `tests/fixtures/gcode/threading_sync.ngc` and `tests/fixtures/canon/threading_sync.events` pin `G33` spindle-synchronized straight feed and `G33.1` rigid tap behavior. - `runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp` now records NURBS G5 canonical boundary calls emitted by vendored `interp_convert.cc::convert_nurbs()`: `NURBS_G5_FEED`. `tests/fixtures/gcode/nurbs_g5_semantics.ngc` and `tests/fixtures/canon/nurbs_g5_semantics.events` pin `G5.2` control-point collection and `G5.3` NURBS feed emission. - `runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp` now records NURBS G6 canonical boundary calls emitted by vendored `interp_convert.cc::convert_nurbs()`: `NURBS_G6_FEED`. `tests/fixtures/gcode/nurbs_g6_semantics.ngc` and `tests/fixtures/canon/nurbs_g6_semantics.events` pin `G6.2` order, interpolation mode, control-point, weight, and K segment handling. - `runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp` now records spindle-orient canonical boundary calls emitted by vendored LinuxCNC conversion and queue code: `ORIENT_SPINDLE` and `WAIT_SPINDLE_ORIENT_COMPLETE`. `tests/fixtures/gcode/spindle_orient.ngc` and `tests/fixtures/canon/spindle_orient.events` pin `M19 R/P/Q` behavior from `interp_convert.cc::convert_m()` and `interp_queue.cc`. - `runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_runtime.cpp` now records tool-table canonical boundary calls emitted by vendored `interp_convert.cc::convert_setup_tool()`: `SET_TOOL_TABLE_ENTRY`. `tests/fixtures/gcode/tool_table_setup.ngc` and `tests/fixtures/canon/tool_table_setup.events` pin `G10 L1` tool offset, diameter, front/back angle, and orientation behavior. - `tests/fixtures/gcode_errors/g1_zero_feed.ngc` and `tests/fixtures/canon_errors/g1_zero_feed.expected` pin the negative `G1` zero-feed case. The source basis is LinuxCNC `interp_convert.cc::convert_straight()` and `rs274ngc_return.hh::NCE_CANNOT_DO_G1_WITH_ZERO_FEED_RATE`. - This proves the current extracted interpreter slice can parse and execute a small fixture set through a standalone canonical event sink. - Important direction change: the minimal wrapper behavior is a migration probe, not the program body. Do not expand it into a separate CNC implementation. The next work must retire hand-written wrapper semantics and move execution through vendored LinuxCNC interpreter source such as `interp_convert.cc`, `interp_read.cc`, `interp_check.cc`, and `interp_execute.cc`. - `tools/build_native_probes.sh` now includes `linuxcnc_interp_convert_source_probe`, which directly compiles vendored `interp_convert.cc`. The required `emcStatus` shim is limited to the native status boundary used by `tag_arc()` for machine units; it is not a project-authored CNC behavior implementation. - `tools/build_native_probes.sh` now also includes direct source compile probes for vendored `interp_read.cc`, `interp_check.cc`, and `interp_execute.cc`. These probes keep the next interpreter-core migration work focused on LinuxCNC source entry points and expose missing standalone runtime shims before wrapper behavior is expanded. - The direct source compile probes now cover the remaining vendored `rs274ngc` interpreter core files used by the standalone harness: `modal_state.cc`, `interp_array.cc`, `interp_internal.cc`, `interp_arc.cc`, `interp_inverse.cc`, `interp_cycles.cc`, `interp_g7x.cc`, `interp_queue.cc`, `interp_find.cc`, `interp_namedparams.cc`, `interp_write.cc`, `interp_o_word.cc`, and `rs274ngc_pre.cc`. `rs274ngc_pre.cc` is compiled with the existing standalone `UNIT_TEST`/`LINUXCNC_STANDALONE_USE_RS274_PRE_STATE` boundary that isolates Python runtime integration from the browser simulation core. - `tools/build_native_probes.sh` now includes direct source compile probes for the vendored LinuxCNC trajectory-planner and posemath files used by `linuxcnc_tp_api_probe`: `tp.c`, `tc.c`, `tcq.c`, `spherical_arc.c`, `blendmath.c`, `sp_scurve.c`, `ruckig_wrapper.c`, the selected `cruckig/*.c` sources, `emcpose.c`, `posemath.cc`, `_posemath.c`, and `sincos.c`. These probes use the same `TP_FLAGS` as the standalone TP harness, including the existing `-fpermissive` boundary required by upstream enum conversions in `tp.c`. - `tools/verify_vendor_sync.sh` now validates the LinuxCNC source extraction boundary before native probes run. It rejects duplicate manifest entries, missing or extra vendored files, and byte-level drift between each manifest file under `vendor/linuxcnc/` and the matching file under `../linuxcnc/`. `tools/source-manifest.txt` was also de-duplicated so the manifest is a single authoritative extraction list. - Direct source compile probes now also cover vendored `interp_base.cc` and `gomath.c`. `interp_base.cc` uses a standalone `EMC2_HOME` compile-time path boundary for LinuxCNC's dynamic interpreter lookup, and `gomath.c` is compiled as C with `gcc` so its LinuxCNC C linkage is preserved. The standalone `rtapi.h` shim was made C/C++ compatible for this C-source boundary without changing vendored LinuxCNC files. - `inifile.cc` now has its own direct source compile probe in addition to the existing INI parser harness. With this probe, every `.c` and `.cc` file listed in `tools/source-manifest.txt` has a native source-level compile check under the standalone build boundary. - `tools/build_native_probes.sh` now emits `build/native/source-probes.tsv` while compiling vendored `*_source_probe` targets. The native verification script compares that map against every `.c` and `.cc` entry in `tools/source-manifest.txt`, so future LinuxCNC source additions fail validation unless they also get an explicit standalone source compile probe. ## Phase 4: Port INI Parsing Without Editing Upstream Purpose: Move LinuxCNC config parsing into the standalone runtime. Steps: 1. Vendor: - `../linuxcnc/src/emc/ini/inifile.cc` - `../linuxcnc/src/emc/ini/inifile.hh` - `../linuxcnc/src/emc/ini/inifile.h` 2. Add shim headers under `wasm-port/runtime/core/shims/` for small dependencies only. 3. Replace file loading through: - wrapper-level adapter, preferred - minimal vendored patch only if unavoidable 4. Preserve: - `#INCLUDE` - relative includes - recursion checks - line continuation - duplicate section merge behavior - typed query behavior 5. Add tests for INI semantics under `tests/native/`. Involved LinuxCNC source: - `src/emc/ini/inifile.cc` - `src/emc/ini/inifile.hh` - `src/emc/ini/inifile.h` ## Phase 5: Port Parameter Tables and Variable Files Purpose: Preserve LinuxCNC numeric parameter behavior exactly enough for simulation. Steps: 1. Vendor: - `../linuxcnc/src/emc/rs274ngc/interp_parameter_def.hh` - `../linuxcnc/src/emc/rs274ngc/interp_array.cc` - `../linuxcnc/src/emc/rs274ngc/interp_internal.hh` - `../linuxcnc/src/emc/rs274ngc/rs274ngc_pre.cc` 2. Extract: - `setup.parameters[]` - `required_parameters[]` - `readonly_parameters[]` - parameter file load/save logic 3. Replace native file writes with a standalone file service abstraction. 4. Keep LinuxCNC’s parameter text format in phase 1. 5. Add regression tests for: - missing file - out-of-order parameters - zero-fill behavior - required parameter persistence - read-only protection Involved LinuxCNC source: - `src/emc/rs274ngc/interp_parameter_def.hh` - `src/emc/rs274ngc/interp_array.cc` - `src/emc/rs274ngc/interp_internal.hh` - `src/emc/rs274ngc/rs274ngc_pre.cc` ## Phase 6: Port Named Parameters and Interpreter State Purpose: Preserve LinuxCNC variable semantics and controller-visible state. Steps: 1. Vendor: - `../linuxcnc/src/emc/rs274ngc/interp_namedparams.cc` - `../linuxcnc/src/emc/rs274ngc/interp_internal.hh` - `../linuxcnc/src/emc/rs274ngc/interp_fwd.hh` - selected interpreter files needed by setup/state handling 2. Preserve: - `context.named_params` - `PA_READONLY` - `PA_GLOBAL` - `PA_USE_LOOKUP` - `PA_FROM_INI` - built-in named parameters from `init_named_parameters()` 3. Preserve lookup order: - local - global - `_ini[...]` - `_hal[...]` - optional Python providers later 4. Export state outward rather than redesigning it in JS. 5. Add regression cases for: - local/global scoping - built-in state variables - `_ini[...]` - `_hal[...]` - read-only errors Involved LinuxCNC source: - `src/emc/rs274ngc/interp_namedparams.cc` - `src/emc/rs274ngc/interp_internal.hh` - `src/emc/rs274ngc/interp_fwd.hh` - `src/emc/rs274ngc/interpmodule.cc` ## Phase 7: Replace HAL Runtime With a Simulation HAL Adapter Purpose: Keep LinuxCNC interpreter-visible HAL behavior without migrating HAL itself. Steps: 1. Do not vendor the whole HAL runtime as a target runtime dependency. 2. Use LinuxCNC HAL source as reference only for interface semantics: - `../linuxcnc/src/hal/hal.h` - `../linuxcnc/src/hal/halmodule.cc` - `../linuxcnc/src/emc/ini/inihal.cc` 3. Define a standalone HAL adapter interface: - lookup by name - typed numeric value - connection/existence status 4. Make `_hal[...]` reads resolve through this adapter. 5. Seed the adapter from simulation config and runtime state. 6. Add tests for: - existing names - missing names - disconnected signals - type conversion Involved LinuxCNC source: - `src/hal/hal.h` - `src/hal/halmodule.cc` - `src/emc/rs274ngc/interp_namedparams.cc` - `src/emc/ini/inihal.cc` ## Phase 8: Port the Interpreter Core Purpose: Build the standalone G-code execution engine without touching upstream files. Steps: 1. Vendor selected files from `../linuxcnc/src/emc/rs274ngc/`. 2. Keep original source as intact as possible in `vendor/`. 3. Add wrappers or minimal patches only in the standalone area. 4. Replace these external edges: - file open/read - world sync - HAL reads - logging - runtime callbacks 5. Preserve: - modal state - subroutines - offsets - tool handling - parameter interactions - error semantics 6. Add a canonical event sink interface in standalone code. Involved LinuxCNC source: - `src/emc/rs274ngc/interp_execute.cc` - `src/emc/rs274ngc/interp_read.cc` - `src/emc/rs274ngc/interp_check.cc` - `src/emc/rs274ngc/interp_convert.cc` - `src/emc/rs274ngc/interp_cycles.cc` - `src/emc/rs274ngc/interp_find.cc` - `src/emc/rs274ngc/interp_write.cc` - `src/emc/rs274ngc/interp_o_word.cc` - `src/emc/rs274ngc/rs274ngc_pre.cc` - `src/emc/rs274ngc/rs274ngc_interp.hh` ## Phase 9: Port Planner and Kinematics Purpose: Preserve LinuxCNC motion planning and 5-axis simulation behavior. Steps: 1. Vendor selected planner files from `../linuxcnc/src/emc/tp/`. 2. Vendor selected kinematics files from: - `../linuxcnc/src/emc/kinematics/` - selected `.comp` sources mirrored into standalone code where needed 3. Replace loadable-module assumptions with a registry in the standalone runtime. 4. Keep original math and state logic intact as far as practical. 5. Add tests for: - planner outputs - forward/inverse kinematics - 5-axis world/joint transforms Involved LinuxCNC source: - `src/emc/tp/tp.c` - `src/emc/tp/tc.c` - `src/emc/tp/tcq.c` - `src/emc/tp/blendmath.c` - `src/emc/tp/sp_scurve.c` - `src/emc/tp/ruckig_wrapper.c` - `src/emc/kinematics/*.c` - `src/hal/components/xyzab_tdr_kins.comp` - `src/hal/components/xyzacb_trsrn.comp` - `src/hal/components/xyzbca_trsrn.comp` ## Phase 10: Build the Standalone WASM Program Purpose: Keep the migrated program completely outside native LinuxCNC management. Steps: 1. Build the standalone native core first. 2. Add a standalone WASM export layer under: - `wasm-port/runtime/core/` - `wasm-port/runtime/sdk/` 3. Use `vendor/` sources plus standalone wrappers as build input. 4. Do not compile from `../linuxcnc` directly in the final WASM product build. 5. Emit: - `wasm` module - JS loader - standalone SDK Outputs: - independently managed WASM simulation core ## Phase 11: Build the Frontend and OPFS Layer Purpose: Keep the standalone port program separate from LinuxCNC GUI code and storage. Steps: 1. Build frontend files under: - `wasm-port/runtime/ui/` - `wasm-port/runtime/opfs/` 2. Implement: - HTML shell - JavaScript control panel - OPFS persistence - file import/export - machine/controller state views 3. Keep LinuxCNC GUI code reference-only. 4. Ensure the frontend depends only on the standalone SDK, not on native LinuxCNC binaries. Outputs: - standalone browser program ## Phase 12: Validate Drift Against Upstream Purpose: Prove the standalone port still tracks LinuxCNC behavior. Steps: 1. Use native LinuxCNC tests and fixtures as semantic baselines. 2. Compare: - LinuxCNC native behavior - standalone native extracted core - standalone WASM behavior 3. Maintain a drift report. 4. Re-run extraction if upstream source changes. 5. Keep patches small and traceable. Outputs: - drift report - compatibility regression suite ## Management Rules For Daily Development Use these rules continuously: 1. Never edit files under `linuxcnc/` as part of the port. 2. Any needed modification to upstream logic must be applied to vendored copies only. 3. Any upstream sync must be script-driven and repeatable. 4. Every shim must be documented. 5. Every local patch against vendored source must be stored as a patch file or clearly isolated wrapper. ## Recommended Document Set Keep these documents under `wasm-port/docs/`: - `scope-and-baseline.md` - `source-reuse-map.md` - `state-porting-strategy.md` - `wasm-build-strategy.md` - `frontend-architecture.md` - `opfs-file-model.md` - `compatibility-validation.md` - `drift-report.md` ## Immediate Next Step Continue expanding the standalone interpreter core from the verified minimal traverse path: 1. replace the temporary minimal `convert_g()` implementation with calls into vendored LinuxCNC interpreter conversion code. 2. identify and shim the native runtime symbols blocking direct compilation of `interp_convert.cc`, `interp_execute.cc`, and related interpreter files. 3. keep fixture coverage as regression protection while deleting temporary hand-written semantics. 4. keep all source changes inside `wasm-port/` and leave `../linuxcnc/` read-only.