docs: map reusable laser software ecosystem
Document the existing JCZ/MOPA implementation in MeerK40t, the Rayforge host-platform opportunity, alternatives, risks, and offline proof gates. Reframe the roadmap around validating reuse before building a new desktop stack.
This commit is contained in:
parent
2059fe90e6
commit
a54a160631
4 changed files with 568 additions and 29 deletions
|
|
@ -23,7 +23,9 @@ Start with:
|
|||
- [LightBurn collection checklist](docs/collection/lightburn.md)
|
||||
- [Sanitized machine profile](docs/research/machine-profile.yaml)
|
||||
- [110/300 configuration comparison](docs/research/config-comparison.md)
|
||||
- [Open-source reuse landscape](docs/research/open-source-landscape.md)
|
||||
- [Repository boundary decision](docs/adr/0001-public-private-repository-boundary.md)
|
||||
- [Proposed Rayforge/BalorMK reuse decision](docs/adr/0002-reuse-rayforge-and-balormk.md)
|
||||
- [Current Phase 0 status](docs/status/phase-0.md)
|
||||
|
||||
## Validation
|
||||
|
|
|
|||
87
docs/adr/0002-reuse-rayforge-and-balormk.md
Normal file
87
docs/adr/0002-reuse-rayforge-and-balormk.md
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
# ADR 0002: Prove reuse of Rayforge and BalorMK before building an app
|
||||
|
||||
- Status: Proposed
|
||||
- Date: 2026-10-17
|
||||
|
||||
## Context
|
||||
|
||||
The initial roadmap assumed that The Pirate Ray would define its own offline
|
||||
application core and would later research the JCZ protocol. Ecosystem research
|
||||
found two MIT-licensed projects that substantially change that assumption:
|
||||
|
||||
- Rayforge already implements most of the desired cross-platform desktop
|
||||
product and has an addon/driver architecture, LightBurn import, simulation,
|
||||
material recipes, pre-flight validation, and MOPA-relevant operation fields.
|
||||
- MeerK40t's BalorMK already implements the EZCAD2-compatible JCZ controller
|
||||
protocol, MOPA pulse width, a mock connection, and the exact USB VID/PID
|
||||
independently observed in our installer evidence.
|
||||
|
||||
Creating another editor, geometry stack and controller implementation would
|
||||
duplicate large, safety-relevant bodies of work and permanently increase the
|
||||
maintenance burden.
|
||||
|
||||
## Proposed decision
|
||||
|
||||
Do not begin independent desktop product implementation. First run three
|
||||
offline, version-pinned proofs:
|
||||
|
||||
1. evaluate stock MeerK40t with BalorMK's mock controller as the shortest
|
||||
route to a usable product;
|
||||
2. prove that an external Rayforge addon can register a binary no-device
|
||||
driver and survive packaging on Windows;
|
||||
3. translate one synthetic Rayforge operation stream to JCZ/Balor commands and
|
||||
compare it with a BalorMK mock trace.
|
||||
|
||||
If the proofs pass, prefer one of these outcomes in order:
|
||||
|
||||
1. use and contribute to MeerK40t if its full application is adequate;
|
||||
2. implement and upstream a Rayforge JCZ/Balor addon, adapting the narrowest
|
||||
practical layer from BalorMK;
|
||||
3. extract a small maintained controller library shared by either application.
|
||||
|
||||
An independent desktop application requires a later ADR showing concrete,
|
||||
tested gaps in both existing applications.
|
||||
|
||||
No copied upstream source enters this repository until the project license is
|
||||
chosen and exact commit-level copyright/license attribution is recorded.
|
||||
|
||||
## Proof obligations
|
||||
|
||||
- All experiments are mock/no-I/O and cannot enumerate or open USB devices.
|
||||
- Frequency and pulse-width units and defaults survive end-to-end.
|
||||
- Galvo coordinates, correction, timing, list buffering, framing, cancel and
|
||||
status semantics fit the host abstraction or their required extensions are
|
||||
explicit.
|
||||
- The adapter emits deterministic traces suitable for golden tests.
|
||||
- Hardware transport is optional, disabled by default, and separated from
|
||||
encoding.
|
||||
- Machine/source/lens/profile mismatch fails closed.
|
||||
- Windows driver switching is excluded from automatic setup.
|
||||
- Upstream contribution feasibility and API stability are assessed before a
|
||||
permanent fork is accepted.
|
||||
|
||||
## Consequences if accepted
|
||||
|
||||
- The project becomes an integration, validation and safety effort rather
|
||||
than a general CAD application effort.
|
||||
- M1 is shortened to ecosystem validation and a JCZ vertical slice.
|
||||
- Protocol capture is a fallback used only for unresolved behavior, not the
|
||||
first discovery method.
|
||||
- The eventual public repository may primarily contain an addon, machine
|
||||
profiles, tests, fixtures and documentation.
|
||||
- Project license selection becomes a prerequisite for adapted code. MIT is
|
||||
the simplest compatibility candidate, but this ADR does not select it.
|
||||
|
||||
## Rejection criteria
|
||||
|
||||
Reject the proposed Rayforge route if the addon seam cannot support a binary
|
||||
galvo driver without maintaining invasive core changes, or if the operation
|
||||
model loses required galvo/MOPA semantics. Reject the stock MeerK40t route if
|
||||
the tested application cannot provide a safe and maintainable workshop
|
||||
workflow. Record evidence before choosing a standalone app.
|
||||
|
||||
## Research basis
|
||||
|
||||
See [Open-source landscape](../research/open-source-landscape.md) for the
|
||||
candidate matrix, inspected commits, risks and detailed spike plan.
|
||||
|
||||
440
docs/research/open-source-landscape.md
Normal file
440
docs/research/open-source-landscape.md
Normal file
|
|
@ -0,0 +1,440 @@
|
|||
# Open-source landscape for The Pirate Ray
|
||||
|
||||
- Research date: 2026-10-17
|
||||
- Scope: reusable software for a JPT E2/M7 MOPA fiber laser on a
|
||||
JCZ/EZCAD2-compatible controller, followed by possible CO2 backends
|
||||
- Method: public project documentation, source inspection, tests, release
|
||||
history, and small shallow/sparse source checkouts; no vendor executable was
|
||||
run and no laser or USB device was contacted
|
||||
|
||||
## Executive conclusion
|
||||
|
||||
The project should **not** begin by writing a LightBurn clone or reverse
|
||||
engineering the complete JCZ protocol from scratch. Two MIT-licensed projects
|
||||
already cover most of the problem from opposite directions:
|
||||
|
||||
1. [MeerK40t](https://github.com/meerk40t/meerk40t), specifically its
|
||||
`balormk` module, already controls EZCAD2-compatible JCZ galvo controllers,
|
||||
includes MOPA pulse-width support, and has a mock USB connection. Its USB
|
||||
implementation uses VID `9588`, PID `9899`, write endpoint `0x02`, and read
|
||||
endpoint `0x88`. The VID/PID exactly match the values independently found
|
||||
in our private installer evidence.
|
||||
2. [Rayforge](https://github.com/barebaric/rayforge) already supplies the
|
||||
actively developed desktop editor, project model, geometry/toolpath
|
||||
pipeline, LightBurn project and device import, material recipes,
|
||||
simulation, pre-flight checks, packaging, and addon architecture. Its
|
||||
neutral operation model and UI already represent laser frequency and pulse
|
||||
width. It does not currently provide a JCZ driver.
|
||||
|
||||
The leading architecture is therefore a **Rayforge JCZ/Balor backend or
|
||||
addon**, with command semantics adapted from the current BalorMK
|
||||
implementation. Before committing to that architecture, stock MeerK40t should
|
||||
also be evaluated as the shortest route to a usable open-source application.
|
||||
An independent desktop application is the fallback, not the starting point.
|
||||
|
||||
This is a research recommendation, not yet an architecture decision. The
|
||||
proposed decision and its proof obligations are recorded in
|
||||
[ADR 0002](../adr/0002-reuse-rayforge-and-balormk.md).
|
||||
|
||||
## What the project actually needs
|
||||
|
||||
The useful unit of reuse is larger than a USB library. A workshop application
|
||||
needs all of the following:
|
||||
|
||||
| Capability | Importance for the JPT | Existing best candidate |
|
||||
| --- | --- | --- |
|
||||
| JCZ discovery, USB transport and command encoding | Critical | MeerK40t BalorMK |
|
||||
| Galvo job sequencing, timing, status and abort | Critical | MeerK40t BalorMK |
|
||||
| MOPA frequency and pulse-width representation | Critical | Both projects |
|
||||
| Lens correction and coordinate mapping | Critical | BalorMK as reference; must validate against our profiles |
|
||||
| Mock controller and deterministic traces | Critical before hardware | BalorMK mock plus a new adapter-level fake |
|
||||
| Desktop canvas, document and undo/redo | Large effort | Rayforge |
|
||||
| SVG/DXF/PDF/raster and LightBurn import | Large effort | Rayforge |
|
||||
| Geometry, hatch, offsets and path planning | Large effort | Rayforge plus raygeo |
|
||||
| Machine profiles, materials and recipes | Large effort | Rayforge |
|
||||
| Preview, simulation and pre-flight checks | Safety-relevant | Rayforge, extended for galvo semantics |
|
||||
| Packaging for Windows | Required | Both ship desktop builds; Rayforge is the preferred modern base |
|
||||
| Future Ruida support | Relevant to the CO2 machines if confirmed | Rayforge/ruida-pa or MeerK40t; controller identity still unknown |
|
||||
|
||||
## Candidate assessment
|
||||
|
||||
The classifications mean:
|
||||
|
||||
- **adopt**: evaluate as a product or direct maintained dependency;
|
||||
- **adapt**: use code or concepts behind a narrow interface, with attribution;
|
||||
- **reference**: learn from it, but do not make it a primary dependency;
|
||||
- **defer/reject**: does not solve the current controller problem well enough.
|
||||
|
||||
| Candidate | License | JCZ/MOPA | Desktop/product coverage | Maintenance signal at snapshot | Disposition |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| MeerK40t | MIT | Direct EZCAD2/JCZ; MOPA support | Full app, older wxPython architecture | Project declares maintenance mode, but still receives changes | **Adopt/evaluate now** and **adapt BalorMK** |
|
||||
| BalorMK in MeerK40t | MIT at repository root; upstream documents its rewrite history | Direct, exact controller family | Controller, driver and limited galvo UI | Current code in main | **Primary protocol baseline** |
|
||||
| galvoplotter | MIT | Direct low-level LMC; fiber and CO2 | Library only | Latest PyPI release found is old/beta | Prototype/reference; current BalorMK is ahead |
|
||||
| Rayforge | MIT | No JCZ driver yet; neutral model already has MOPA fields | Broad modern app | Very active, current source and releases | **Preferred host platform, pending spike** |
|
||||
| raygeo | MIT | Hardware-neutral | High-performance geometry kernel | Active and used by Rayforge | Adopt through Rayforge; direct use only if needed |
|
||||
| ruida-pa | MIT | No JCZ | Binary Ruida backend | Active and used by Rayforge | Future CO2 candidate after controller identification |
|
||||
| VisiCut / LibLaserCut | LGPL family | No credible JCZ path found | Mature Java architecture and drivers | Long-running project | Reference for abstractions |
|
||||
| LaserWeb4 | AGPL-3.0 | No JCZ support found | Electron/web laser UI | Older ecosystem | Defer; weaker fit and license implications |
|
||||
| lbrnts | MIT | File format only | TypeScript LightBurn parse/write | Small focused project | Reference if round-trip writing becomes necessary |
|
||||
| lbrn2-to-svg | Open repository; verify exact license before reuse | File format only | Narrow conversion | Small project | Reference; Rayforge already imports `.lbrn2` |
|
||||
| USBLM-V1 MeerK40t replacement | Open repository | Related JCZ hardware, but VID/PID `9588:9999` rather than ours | Firmware/stack-specific | Niche | Reference only; not our identified device |
|
||||
| MarkEzd/EZCAD SDK wrappers | Often open wrapper code around proprietary DLLs | Direct through vendor DLL | Windows-only API wrappers | Depends on opaque vendor binary | Do not use as the public product foundation |
|
||||
|
||||
Repository activity is a maintenance indicator, not a security or quality
|
||||
guarantee. License labels are project-declared and must be rechecked at the
|
||||
exact commit before code is copied or distributed.
|
||||
|
||||
## Finding 1: MeerK40t can probably talk to this controller today
|
||||
|
||||
[MeerK40t describes itself](https://github.com/meerk40t/meerk40t) as an
|
||||
MIT-licensed, cross-platform laser application and explicitly lists
|
||||
EZCAD2-compatible JCZ galvo lasers among supported devices. Its current
|
||||
`balormk` module is not a placeholder:
|
||||
|
||||
- `usb_connection.py` uses PyUSB/libusb and the exact `9588:9899` identity
|
||||
present in our sanitized machine profile;
|
||||
- `controller.py` implements the LMC command layer, command lists, status,
|
||||
delays, power, frequency, MOPA pulse width, wait and abort behavior;
|
||||
- `driver.py` translates MeerK40t cut operations into galvo jobs;
|
||||
- `device.py` exposes laser-source, correction, timing and pulse-width
|
||||
settings;
|
||||
- `mock_connection.py` records traffic without contacting hardware;
|
||||
- the plugin registers a MOPA-capable fiber device.
|
||||
|
||||
The upstream [BalorMK documentation](https://github.com/meerk40t/meerk40t/blob/main/meerk40t/balormk/README.md)
|
||||
states support for JCZ EZCAD2, fiber MOPA, power/frequency/pulse timing,
|
||||
calibration and a simulation interface. The
|
||||
[USB source](https://github.com/meerk40t/meerk40t/blob/main/meerk40t/balormk/usb_connection.py)
|
||||
is especially strong corroborating evidence because its identifiers were
|
||||
found independently rather than inferred from the project.
|
||||
|
||||
This changes M3 in the original roadmap. Protocol work should begin by
|
||||
validating and testing an existing independent implementation, not by passive
|
||||
capture or blank-sheet reverse engineering.
|
||||
|
||||
### Limits and risks
|
||||
|
||||
- MeerK40t explicitly says it is in maintenance mode and warns that weekly
|
||||
builds can regress. A known stable release and a pinned source commit must
|
||||
be evaluated separately.
|
||||
- The low-level controller is embedded in MeerK40t service and cut-code
|
||||
abstractions. Copying only `driver.py` would not produce a clean standalone
|
||||
library.
|
||||
- The current module has a mock transport, but its hardware-safety behavior
|
||||
and test depth do not meet this project's intended fail-closed standard.
|
||||
- Source comments and compatibility branches show uncertainty around some
|
||||
controller/source variants. “EZCAD2 compatible” is not proof that every
|
||||
setting is correct for our JPT source, scan head and lens.
|
||||
- The driver includes commands capable of moving the galvos and enabling
|
||||
emission. It is evidence and reusable code, not a safety certification.
|
||||
|
||||
### `galvoplotter`: cleaner boundary, older implementation
|
||||
|
||||
[galvoplotter](https://github.com/meerk40t/galvoplotter) is an MIT-licensed,
|
||||
PyUSB-based low-level library for EZCAD2 LMC controllers. It has controller,
|
||||
connection, spooler and job abstractions and was explicitly designed for
|
||||
embedding. That makes its package boundary attractive.
|
||||
|
||||
The drawback is age: the latest package found on
|
||||
[PyPI](https://pypi.org/project/galvoplotter/) is the beta `0.2.0` release
|
||||
from 2023, while BalorMK has continued evolving and explicitly contains MOPA
|
||||
support. It should be used to understand the smallest viable API, not pinned
|
||||
blindly as the production backend. A good upstream outcome could be helping
|
||||
extract today's BalorMK controller into a maintained standalone package.
|
||||
|
||||
## Finding 2: Rayforge already is most of the desired application
|
||||
|
||||
[Rayforge](https://github.com/barebaric/rayforge) is an MIT-licensed,
|
||||
cross-platform Python/GTK4 desktop application. Current functionality includes
|
||||
a 2D editor, layers, material recipes, projects, SVG/DXF/PDF/raster import,
|
||||
3D toolpath simulation, rotary support, cameras, pre-flight bounds/no-go-zone
|
||||
checks, and packaged Windows builds. It already imports LightBurn projects and
|
||||
device profiles.
|
||||
|
||||
Source inspection found particularly relevant implementation details:
|
||||
|
||||
- `.lbrn`/`.lbrn2` parsing covers shapes, paths, transforms, images and text
|
||||
backup paths;
|
||||
- imported LightBurn cut settings are mapped into Rayforge workflows,
|
||||
including speed, power, passes, offsets, raster interval/angle and dither;
|
||||
- `.lbdev` device profiles have a separate importer;
|
||||
- laser steps and recipes serialize `frequency` in Hz and `pulse_width` in
|
||||
microseconds;
|
||||
- the neutral `Ops` command set contains frequency and pulse-width commands;
|
||||
- binary rather than G-code drivers are supported through an `OpsEncoder`;
|
||||
- driver state, cancel/hold, discovery, machine profiles, simulator and
|
||||
maturity warnings already exist.
|
||||
|
||||
Rayforge's [driver guide](https://rayforge.org/docs/developer/driver/) defines
|
||||
separate encoder, pipeline, transport and asynchronous driver roles. Its
|
||||
[addon guide](https://rayforge.org/docs/developer/addon-overview/) explicitly
|
||||
describes third-party machine drivers loaded without modifying the core. This
|
||||
is almost the exact integration seam the project needs.
|
||||
|
||||
### Why this is preferable to a new app
|
||||
|
||||
A new desktop app would immediately recreate document serialization,
|
||||
selection and transforms, units, importers, undo/redo, toolpath generation,
|
||||
preview, material management, settings UI, packaging and update work. None of
|
||||
those areas differentiates The Pirate Ray. The differentiating work is:
|
||||
|
||||
- a trustworthy JCZ adapter;
|
||||
- JPT/lens-specific profile validation;
|
||||
- galvo/MOPA safety policy;
|
||||
- reproducible offline and hardware tests;
|
||||
- workshop-focused defaults and documentation.
|
||||
|
||||
Keeping that work in an addon or upstream contribution makes the result useful
|
||||
outside Makerspace Næstved and reduces the permanent maintenance burden.
|
||||
|
||||
### Rayforge integration risks
|
||||
|
||||
- The public addon guide demonstrates `machine_manager.register(...)`, while
|
||||
the inspected current source exposes a module-level `register_driver(...)`
|
||||
registry and did not reveal the documented machine registration call in the
|
||||
loaded paths. This may be documentation drift or an incomplete checkout.
|
||||
A tiny addon-loading test must prove the supported seam before architecture
|
||||
is accepted.
|
||||
- Rayforge currently models much of its world around moving-head/G-code
|
||||
machines. Galvo framing, list buffering, correction files, timing delays,
|
||||
infinite “red light” preview and coordinate transforms need an explicit fit
|
||||
analysis.
|
||||
- GTK4/Libadwaita is a substantial Windows packaging dependency stack, even
|
||||
though the project publishes Windows builds.
|
||||
- The addon API is evolving. The manifest API and Rayforge/raygeo versions
|
||||
must be pinned and compatibility tested.
|
||||
- Existing frequency and pulse-width fields are necessary but not sufficient:
|
||||
their units, zero/default semantics and allowed ranges must be checked
|
||||
end-to-end against the JPT source.
|
||||
|
||||
## Finding 3: do not build a geometry engine
|
||||
|
||||
[raygeo](https://github.com/barebaric/raygeo) is Rayforge's MIT-licensed Rust
|
||||
and PyO3 geometry library with Windows/macOS/Linux wheels. It already supplies
|
||||
path construction, arcs and Beziers, boolean and offset operations, fitting,
|
||||
nesting, raster modulation, smoothing, linearization, geometric queries and
|
||||
cylindrical transforms.
|
||||
|
||||
If Rayforge is adopted, use raygeo through Rayforge's model rather than
|
||||
inventing a competing neutral geometry model. If Rayforge is rejected after
|
||||
the spike, raygeo remains a strong direct dependency candidate, subject to API
|
||||
stability and binary-wheel review.
|
||||
|
||||
## Finding 4: LightBurn migration is mostly an extension problem
|
||||
|
||||
Rayforge's existing LightBurn import removes the need to create a general
|
||||
`.lbrn2` parser. The focused task is to build a private, known-working fixture
|
||||
matrix and identify which galvo-specific fields are currently dropped.
|
||||
|
||||
Likely gaps to test include:
|
||||
|
||||
- MOPA pulse width and frequency on every operation type;
|
||||
- hatch modes, cross-hatch order and galvo-specific timing;
|
||||
- device origin, field size and lens correction references;
|
||||
- text fidelity when only a `BackupPath` is portable;
|
||||
- layer ordering and mark-count semantics;
|
||||
- LightBurn units and default/omitted value behavior.
|
||||
|
||||
The small TypeScript project [lbrnts](https://github.com/tscircuit/lbrnts)
|
||||
supports parsing and writing LightBurn files and may be useful as an
|
||||
independent behavioral comparison if round-trip export becomes important. It
|
||||
does not justify adding a JavaScript runtime to the initial Python stack.
|
||||
|
||||
## Finding 5: Windows USB driver handling is a product requirement
|
||||
|
||||
BalorMK uses PyUSB/libusb. The installed EZCAD/LightBurn stack normally uses a
|
||||
Windows vendor driver. Only one driver can own the relevant interface, so a
|
||||
Zadig/libusb change may make the current production software stop seeing the
|
||||
laser until it is reverted.
|
||||
|
||||
[meerk40t-pnputil](https://github.com/meerk40t/meerk40t-pnputil) is an
|
||||
MIT-licensed proof of concept for switching Windows drivers. It is evidence
|
||||
that reversible handling is possible, not production code we should silently
|
||||
run. Before live testing, record the current driver package and create a
|
||||
documented rollback procedure. Driver changes require explicit operator
|
||||
approval and are outside the current offline phase.
|
||||
|
||||
## Future CO2 machines
|
||||
|
||||
Do not infer the Eduard or Bodor controller from the machine brand. Physically
|
||||
identify controller model, connection type and firmware first.
|
||||
|
||||
If either machine uses Ruida, Rayforge already integrates the MIT-licensed
|
||||
[ruida-pa](https://github.com/StevenIsaacs/ruida-pa) project and MeerK40t also
|
||||
has Ruida support. That could make a shared Rayforge platform even more
|
||||
valuable. If the machines use another controller family, repeat this landscape
|
||||
and evidence process for that controller.
|
||||
|
||||
## Proprietary vendor SDKs are not the main path
|
||||
|
||||
EZCAD/MarkEzd SDK wrappers found in public repositories usually expose an open
|
||||
wrapper around a proprietary `MarkEzd.dll`. That may provide useful names and
|
||||
semantic clues, but it does not give us an auditable, cross-platform, freely
|
||||
redistributable controller stack. It also retains the vendor driver and
|
||||
hardware-lock assumptions.
|
||||
|
||||
The public product should therefore not load or redistribute a copied vendor
|
||||
DLL. Any future use of official SDK documentation must be separately reviewed
|
||||
for license, provenance and clean-room implications.
|
||||
|
||||
## Recommended architecture to prove
|
||||
|
||||
```text
|
||||
Rayforge UI / documents / imports / recipes / simulation
|
||||
|
|
||||
raygeo Ops
|
||||
|
|
||||
ThePirateRay JCZ adapter boundary
|
||||
/ \
|
||||
deterministic fake Balor transport
|
||||
and trace sink (adapted from current BalorMK)
|
||||
|
|
||||
explicit hardware gate
|
||||
|
|
||||
JCZ 9588:9899 controller
|
||||
```
|
||||
|
||||
The adapter must keep protocol output separate from transport. The same
|
||||
synthetic job must be encodable into a deterministic trace without importing
|
||||
PyUSB or discovering hardware. Hardware transport is an optional component and
|
||||
is disabled by default in development and CI.
|
||||
|
||||
The first public build should not expose arbitrary raw controller commands.
|
||||
Machine identity, correction/profile hash, lens, field size and source type
|
||||
must agree before a hardware job can be armed.
|
||||
|
||||
## Reuse boundaries
|
||||
|
||||
### Reuse directly or contribute upstream
|
||||
|
||||
- Rayforge application, document, import, recipe, simulation and packaging;
|
||||
- raygeo through Rayforge;
|
||||
- Rayforge's `Ops`, binary encoder and asynchronous driver contracts;
|
||||
- BalorMK command constants, packet semantics and mock-derived test vectors,
|
||||
after exact-license and attribution review;
|
||||
- PyUSB only behind the real hardware transport.
|
||||
|
||||
### Rewrite narrowly for fit and safety
|
||||
|
||||
- the Rayforge-to-Balor operation encoder;
|
||||
- a small controller facade that does not depend on MeerK40t kernel services;
|
||||
- validation of JPT frequency/pulse-width ranges and units;
|
||||
- correction/profile loading with provenance and fail-closed matching;
|
||||
- structured, redacted diagnostics;
|
||||
- a hardware capability gate and test protocol.
|
||||
|
||||
### Do not build now
|
||||
|
||||
- a new canvas or general CAD system;
|
||||
- a new SVG/DXF/PDF importer suite;
|
||||
- a new geometry/boolean/hatch kernel;
|
||||
- a new material database UI;
|
||||
- a general LightBurn parser;
|
||||
- a blank-sheet JCZ protocol implementation;
|
||||
- an auto-installer that changes Windows USB drivers;
|
||||
- support for all three lasers before their controllers are identified.
|
||||
|
||||
## Offline proof plan
|
||||
|
||||
No USB access, framing or emission is needed for these experiments.
|
||||
|
||||
### Spike A — stock MeerK40t
|
||||
|
||||
1. Pin stable MeerK40t and the inspected source commit.
|
||||
2. Run only its mock controller in an isolated configuration directory.
|
||||
3. Create a synthetic square plus hatch job with explicit power, speed,
|
||||
frequency and pulse width.
|
||||
4. Save the mock command stream as a test artifact with upstream version.
|
||||
5. Assess whether the existing app already meets enough workshop needs to
|
||||
prefer a small fork/contribution over a second frontend.
|
||||
|
||||
Go if mock execution is deterministic, the MOPA parameters survive the full
|
||||
pipeline, and the UI/product gap is acceptable. Stop and document any path
|
||||
that tries to enumerate real USB devices in mock mode.
|
||||
|
||||
### Spike B — Rayforge addon seam
|
||||
|
||||
1. Pin Rayforge at the inspected commit.
|
||||
2. Create the smallest external addon that registers a no-device binary
|
||||
driver.
|
||||
3. Prove install, discovery, enable/disable, project reload and packaging on
|
||||
Windows.
|
||||
4. Resolve the documented `machine_manager.register` versus source-level
|
||||
`register_driver` discrepancy with a test or upstream clarification.
|
||||
|
||||
Go if an external addon can own a binary driver without patching core. If a
|
||||
small upstream patch is needed and maintainers accept the design, that is also
|
||||
a go. A permanent private fork is less attractive but still cheaper than a new
|
||||
application.
|
||||
|
||||
### Spike C — golden command equivalence
|
||||
|
||||
1. Construct a tiny Rayforge `Ops` job: move, line, power, speed, frequency,
|
||||
pulse width, delay and end.
|
||||
2. Encode it through a new no-I/O JCZ encoder.
|
||||
3. Generate the equivalent BalorMK mock trace.
|
||||
4. Compare semantic commands and packet bytes, documenting intentional
|
||||
differences.
|
||||
5. Add negative cases for wrong profile, out-of-field geometry, unsupported
|
||||
commands, invalid MOPA ranges and cancellation.
|
||||
|
||||
Go if the adapter can stay small and deterministic. Do not connect the USB
|
||||
transport as part of this spike.
|
||||
|
||||
### Spike D — LightBurn fixture coverage
|
||||
|
||||
1. Use sanitized synthetic projects plus private known-working projects.
|
||||
2. Inventory every source field and its imported representation.
|
||||
3. Add public synthetic regression fixtures for missing galvo/MOPA concepts.
|
||||
4. Propose upstream Rayforge importer changes where generally useful.
|
||||
|
||||
## Decision gates
|
||||
|
||||
Choose **stock/forked MeerK40t** when its existing workflow is acceptable and
|
||||
the fastest usable deployment outweighs UI modernization.
|
||||
|
||||
Choose **Rayforge plus a JCZ addon** when Spike B proves the extension seam and
|
||||
Spike C shows that galvo semantics fit without invasive core changes. This is
|
||||
the current preferred long-term result.
|
||||
|
||||
Choose a **small standalone controller library** only if the controller code
|
||||
cannot responsibly live in either upstream. It should still be usable by both
|
||||
projects and should not grow a GUI.
|
||||
|
||||
Choose an **independent desktop app** only after written evidence that both
|
||||
full applications fail concrete requirements that cannot reasonably be fixed
|
||||
upstream. “We can build it ourselves” is not sufficient evidence.
|
||||
|
||||
## Version-pinned research snapshot
|
||||
|
||||
Source inspected locally in shallow sparse checkouts:
|
||||
|
||||
- MeerK40t: `d511944e08788e88077727f682957759884ff5ca`
|
||||
(2026-09-25)
|
||||
- Rayforge: `c28918c87f8273dd1d244f5a057addc192807fa5`
|
||||
(2026-10-17)
|
||||
|
||||
The checkouts are an ignored research cache and are not vendored into this
|
||||
repository. Any reused code must later be added deliberately with license,
|
||||
copyright, source commit and modification notices.
|
||||
|
||||
## Source index
|
||||
|
||||
- [MeerK40t repository and project status](https://github.com/meerk40t/meerk40t)
|
||||
- [BalorMK overview](https://github.com/meerk40t/meerk40t/blob/main/meerk40t/balormk/README.md)
|
||||
- [BalorMK USB implementation](https://github.com/meerk40t/meerk40t/blob/main/meerk40t/balormk/usb_connection.py)
|
||||
- [galvoplotter repository](https://github.com/meerk40t/galvoplotter)
|
||||
- [galvoplotter package](https://pypi.org/project/galvoplotter/)
|
||||
- [Rayforge repository](https://github.com/barebaric/rayforge)
|
||||
- [Rayforge driver guide](https://rayforge.org/docs/developer/driver/)
|
||||
- [Rayforge addon guide](https://rayforge.org/docs/developer/addon-overview/)
|
||||
- [raygeo repository](https://github.com/barebaric/raygeo)
|
||||
- [ruida-pa repository](https://github.com/StevenIsaacs/ruida-pa)
|
||||
- [meerk40t-pnputil](https://github.com/meerk40t/meerk40t-pnputil)
|
||||
- [VisiCut](https://visicut.org/)
|
||||
- [LaserWeb4](https://github.com/LaserWeb/LaserWeb4)
|
||||
- [lbrnts](https://github.com/tscircuit/lbrnts)
|
||||
- [USB-LMC-V1 replacement project](https://github.com/Meliadolin/usblm-v1-meerk40t)
|
||||
- [Official LightBurn galvo documentation](https://docs.lightburnsoftware.com/latest/Collections/LightBurnForGalvos/)
|
||||
- [Official EZCAD SDK product page](https://www.ezcad.com/products/ezcad-sdk/page/24/)
|
||||
|
||||
|
|
@ -83,25 +83,35 @@ Exit criteria:
|
|||
- sanitized metadata and new analysis are committed publicly;
|
||||
- both repositories pass their clean-clone validation.
|
||||
|
||||
### M1 — Offline application core
|
||||
### M1 — Reuse validation and offline JCZ vertical slice
|
||||
|
||||
Define technology-independent domain models before choosing hardware APIs:
|
||||
Ecosystem research found that Rayforge already implements most of the desired
|
||||
application and MeerK40t BalorMK already implements the relevant controller.
|
||||
Validate those assets before defining competing application architecture. See
|
||||
the [open-source landscape](research/open-source-landscape.md) and
|
||||
[proposed ADR 0002](adr/0002-reuse-rayforge-and-balormk.md).
|
||||
|
||||
- versioned machine-profile, project, operation, and material-preset schemas;
|
||||
- explicit physical units and coordinate transforms;
|
||||
- geometry bounds and parameter validation;
|
||||
- deterministic job planning and simulation interfaces;
|
||||
- an append-only diagnostic/event model with automatic redaction;
|
||||
- a controller interface with a simulator as its only implementation;
|
||||
- tests built from synthetic fixtures and sanitized evidence.
|
||||
The first work is entirely offline:
|
||||
|
||||
A small desktop technology spike should compare candidate stacks using one
|
||||
vertical slice: open a project, render it, validate it, and run it against the
|
||||
simulator. The stack decision belongs in an ADR after the spike, not before it.
|
||||
- evaluate stock MeerK40t against a synthetic MOPA job using only its mock
|
||||
controller;
|
||||
- prove an external Rayforge addon can register and package a binary
|
||||
no-device driver on Windows;
|
||||
- map a Rayforge operation stream into a deterministic JCZ command trace and
|
||||
compare it with BalorMK output;
|
||||
- test existing LightBurn import with synthetic and private known-working
|
||||
galvo projects;
|
||||
- identify only the missing profile, validation, diagnostic and safety
|
||||
concepts instead of designing replacements for existing ones.
|
||||
|
||||
Exit criteria: a user can complete a representative JPT job workflow offline,
|
||||
and automated tests prove that no production controller backend is linked or
|
||||
reachable.
|
||||
The architecture decision remains proposed until these spikes produce
|
||||
evidence. An independent app requires a documented gap analysis showing why
|
||||
neither existing platform can be extended responsibly.
|
||||
|
||||
Exit criteria: a representative JPT job survives import/planning, MOPA
|
||||
parameters and units, validation and deterministic mock encoding; the chosen
|
||||
host architecture is recorded in an accepted ADR; and automated tests prove
|
||||
that no production controller backend is reachable.
|
||||
|
||||
### M2 — Configuration understanding
|
||||
|
||||
|
|
@ -122,13 +132,13 @@ Exit criteria: the app can report a configuration, explain which claims are
|
|||
observed versus inferred, and detect a wrong-lens or unknown-profile condition
|
||||
without writing to the machine.
|
||||
|
||||
### M3 — Protocol discovery and read-only controller access
|
||||
### M3 — Controller validation and read-only access
|
||||
|
||||
This is a new, explicitly approved hardware-research phase. Begin with focused
|
||||
research into documented APIs and existing clean-room implementations, then
|
||||
use passive observation of known software where necessary. Captures and raw
|
||||
third-party material stay private; derived protocol notes and synthetic tests
|
||||
are public.
|
||||
validation of the existing independent BalorMK implementation. Use passive
|
||||
observation of known software only for specific unresolved behavior. Captures
|
||||
and raw third-party material stay private; derived protocol notes and
|
||||
synthetic tests are public.
|
||||
|
||||
The first real backend capabilities are limited to device enumeration,
|
||||
identity, firmware/capability discovery, and status. Every operation receives
|
||||
|
|
@ -194,16 +204,16 @@ imply compatible safety or control behavior on either CO2 machine.
|
|||
The next work package should be small enough to review in a few commits:
|
||||
|
||||
1. collect the pending LightBurn data from the control PC as one local archive;
|
||||
2. record an ADR for the neutral job model and isolated controller backends;
|
||||
3. define v1 schemas for machine profiles and offline projects;
|
||||
4. implement validation plus a deterministic simulated controller;
|
||||
5. build a minimal desktop vertical slice and use it to decide the UI/runtime
|
||||
stack;
|
||||
6. separately produce a written M3 hardware-research protocol before any USB
|
||||
capture or controller command.
|
||||
2. run the stock MeerK40t mock-controller evaluation;
|
||||
3. prove the Rayforge external-addon and binary-driver registration seam;
|
||||
4. build one no-I/O Rayforge-to-JCZ encoder spike and golden trace comparison;
|
||||
5. test Rayforge's existing LightBurn import against galvo/MOPA fixtures;
|
||||
6. accept, amend or reject ADR 0002 from the results;
|
||||
7. separately produce a written M3 hardware-research protocol before any USB
|
||||
access or controller command.
|
||||
|
||||
Items 2–5 can proceed while item 1 is pending. Hardware work cannot proceed
|
||||
until item 6 is reviewed and the physical setup is ready.
|
||||
Items 2–6 can proceed while item 1 is pending. Hardware work cannot proceed
|
||||
until item 7 is reviewed and the physical setup is ready.
|
||||
|
||||
## Decision rules
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue