CadPal

DWG and DXF to JT
on the machine the drawing lives on

One Windows executable that turns architect and supplier drawings into JT 8.1 assemblies for JT2Go and Siemens Process Simulate. No Python, no CAD licence, no upload, no account. The drawing never leaves the workstation.

318 tests passingJT 8.1 · ISO 14306Windows 7 SP1 · 32-bit
The CadPal desktop window: a CAD Conversion page with an input file panel, output settings set to JT 8.1 tessellated, a conversion report panel, and a single Convert to JT button.

The shipping desktop build. One page, one button.

The Problem

Process Simulate accepts JT and nothing else. The drawings arrive as DWG and DXF.

Commercial converters

about $15,000 per seat, per year

Hard to justify for a handful of conversions a month.

Re-export from the original CAD system

needs the licence for that system

The person holding the licence is rarely the person who needs the JT.

Cloud converters

the drawing has to be uploaded

For plant layouts and supplier geometry, that is often a straight no.

Open-source tooling

LibreDWG and ezdxf, by hand

A toolchain, not a tool. It assumes Python, a shell, and someone to maintain both.

CadPal is the fourth option: one file the engineer double-clicks.

How A Conversion Runs

Four local stages, and the last one is a proof.

The CadPal conversion pipeline. A DWG or DXF drawing enters on the left. Stage one, dwg2dxf from LibreDWG, produces a DXF. Stage two, dxf_extract running on a bundled Python with ezdxf, produces the CIG intermediate model. Stage three, jt-writer, writes JT 8.1. Stage four, jt-verify, parses the file back and checks segments, LODs and geometry counts. The result is a verified .jt. A dashed fallback branch rebuilds damaged DWGs from a dwgread JSON dump.

The writer checks itself

An independent parse-back verifier reads the file the writer just produced and asserts the segment table, LOD structure and geometry counts, instead of trusting the writer's own bookkeeping.

Damaged drawings still convert

When a DWG's block-header ownership chain is broken, a fallback path rebuilds it from a dwgread JSON dump rather than failing the job.

Every run is itemised

The conversion report lists what converted and what was skipped, with a reason per skip. Curved ACIS solids surface as unsupported_curved_solid, never silently dropped.

On Device

The whole engine is inside the executable.

The on-device architecture. Everything runs inside one workstation: an Electron shell starts a Node engine as a hidden child bound to loopback, health-gates it, and injects the port into the user interface. The engine drives the bundled converter tools, which read and write files on the local disk. To the right, the abandoned cloud path is shown severed: the deployed edge function returns HTTP 501 because native converter tooling cannot run on Deno.

Loopback only

In the packaged app the engine binds 127.0.0.1 on a port chosen at boot. Nothing is reachable from the network and nothing calls out.

Tools travel with the app

LibreDWG, every DLL it imports, and a 32-bit Python 3.8.10 with ezdxf are carried inside the executable. There is nothing for the user to install.

The cloud path was removed

Native converter tooling cannot run on Deno, so the Supabase edge function was abandoned and returns HTTP 501 by design. There is nothing left to switch on by accident.

The Windows 7 Target

Every silent failure on the target now has a gate that refuses to ship it again.

The target machine is a Windows 7 SP1 workstation with PowerShell 2.0, no build tools, and no administrator patience. Five faults landed in four days of field testing, each one passing on every developer and CI machine and dying without a message on the target.

Five failures that were silent on the Windows 7 target, each paired with the build gate that now blocks it: a mis-hoisted dependency blocked by verify-packaged-deps.js, a blank window blocked by a relative Vite base and a Chromium 108 target, a sandboxed preload blocked by disabling the preload sandbox, a converter exiting 0xC0000135 blocked by verify-bundled-dlls.js reading PE import tables, and an unshippable build solved by staging a pinned 32-bit Python from macOS.
01

The window never opened

electron-builder 25 rebuilt node_modules from an npm ls tree and put archiver-utils where the top-level zip-stream could not resolve it.

scripts/verify-packaged-deps.js

Applies Node resolution across the packaged tree. dist:win packs, verifies, then packages.

02

A blank white window, no error

Vite's default base of '/' emits absolute asset paths, which resolve to the drive root under loadFile's file:// origin and load nothing.

client/vite.config.js

base: './' plus target: 'chrome108' for Electron 22. Renderer errors now reach the log.

03

The interface never found the engine

Electron 20 and later sandbox preloads, so require of a relative file failed and the renderer was never told which port to call.

electron/main.js

sandbox: false with context isolation kept. Preload errors are logged, not swallowed.

04

Convert did nothing, exit 0xC0000135

The LibreDWG win32 zip omits libwinpthread-1.dll, which libgcc imports. Every developer and CI box hides the gap by having MinGW on PATH.

scripts/verify-bundled-dlls.js

Reads PE import tables and the Windows 7 subsystem ceiling. Failures now name STATUS_DLL_NOT_FOUND.

05

No converting build could be produced at all

Frozen Python sidecars needed a Windows box or CI, and the organisation account was billing-locked, so Actions could not run.

scripts/stage-python-win32.js

Stages a sha256-pinned 32-bit Python 3.8.10 and ezdxf from macOS, straight into the build.

The pattern that worked every round: read the artifact the failure left behind, reproduce it locally, fix it, then add a check that fails the build rather than the customer.

What It Does Today

Shipping, and what is not.

DXF to JT 8.1
Shipping
318 automated tests, plus real-file integration conversions
DWG to JT 8.1
Shipping
A hotel drawing at 19,210 entities, 0 skipped, 217k triangles
Damaged DWG recovery
Shipping
dwgread JSON rebuild when the block-header ownership chain is broken
Annotation fidelity
Shipping
TEXT and MTEXT glyph outlines, DIMENSION explode, 156/156 hatches on that drawing
Viewer acceptance
Passed
JT2Go 13.1.0 and Process Simulate, six review rounds, exact scale verified
Conversion report
Shipping
Every run itemises what converted and what was skipped, with a reason per skip
Windows 7 32-bit build
Shipping
Portable single executable, cross-built from macOS
STL to JT
Working
A 242k-triangle model converted, but not yet on the desktop path
STEP and IGES input
Not shipped
Needs the OpenCASCADE bridge. Phase 1
Cloud conversion
Abandoned
Native tooling cannot run on Deno. The deployed edge function returns HTTP 501

Phase 0, current

On-device DWG and DXF to JT with zero OpenCASCADE. Shipping and in acceptance testing on the target hardware.

Phase 1

STEP and IGES, two-way, through the OpenCASCADE bridge.

Phase 2

CATPart and SAT. Parked, and likely to need a commercial SDK.

Output is JT 8.1 tessellated geometry for visualisation and simulation, not solid modelling. CadPal converts, verifies and reports. It is not a CAD editor.