Skip to content

v0.3.0: stitch-quality fixes, OpenStitch Micro font, satin columns, background stitching - #1

Merged
lb2002 merged 21 commits into
mainfrom
fix/engine-audit
Oct 28, 2026
Merged

lb2002 merged 21 commits into
mainfrom
fix/engine-audit

Conversation

@lb2002

@lb2002 lb2002 commented Oct 28, 2026

Copy link
Copy Markdown
Owner

Summary

An engine audit plus the first round of features that close the gap to commercial digitizing software. The full list is in CHANGELOG.md.

Critical fixes

  • Stray stitches: after a trim inside one colour, the next run was split from the old needle position, sewing stitches of up to 50 mm across the design. This affected every export with more than one run per colour.
  • JEF exports never cut threads: pyembroidery drops trims in JEF by default.
  • Ragged fill edges: the density guard removed tatami row-turn points as "micro-stitches".
  • False round-hoop collision warnings: bounding-box corners overestimated round designs by up to 41 %.

New

  • OpenStitch Micro, a single-stroke font for lettering from 2.5 mm.
  • Satin column tool that stitches perpendicular to the drawn centre line.
  • Satin underlay types (centre/edge/zigzag/edge+zigzag, chosen automatically by width).
  • Fewer trims: hidden travel between underlay and top stitching.
  • Background stitch generation, faster simulator and heatmap, cancelable auto-digitize, unsaved-changes prompt.
  • Rewritten SVG import: transforms, arcs, styles, <use>, fill rules, real size.
  • Robust FAT12 floppy images.
  • Complete DE/EN/FR/ES translation of dialogs, inspector, PDF and Quality Doctor.

Testing

  • 63 automated tests (up from 6), including regression tests that fail on the old code.
  • Export round-trip and orientation checked for DST/PES/JEF/EXP/VP3/U01/XXX.
  • Offscreen smoke test of the full window: drawing a column, micro text, language switch, Quality Doctor, DST export and verification.
  • Not yet tested on a real embroidery machine.

Co-Authored-By: Claude [email protected]

lb2002 and others added 17 commits October 28, 2026 15:43
Engine:
- After a trim + jump inside a colour block, _connect kept splitting
  stitches from the old needle position, sewing stray stitches (up to
  50+ mm) across the design. Continue from run[0] after a jump.
- Prune stitch cache entries of objects that no longer exist.

UI:
- Undo/redo snapshots keep object ids (cache hits, no full regen) and
  restore the selection; spinbox drags coalesce into one undo step,
  no-op edits no longer snapshot; visibility toggle is undoable.
- Deferred rebuild no longer recreates the inspector while typing.
- Hoop/machine combos sync with loaded/imported designs; simulator
  state resets on new designs.
- Auto-digitize no longer reuses a plan built for the default hoop.
- Node editor freezes node indices during a drag, keeps other polygon
  parts, and is disabled for text/stitch objects.
- Fit-to-hoop / scale keep text rotation and handle scale.
- Atomic project save, BOM-tolerant load, error dialogs for save/PDF/
  PNG and non-image files in the image dialogs.

Adds regression tests for each fix.

Co-Authored-By: Claude <[email protected]>
Underlay pieces, the travel to the top-fill entry and the leftover
satin end-cap fills are stitched over afterwards, so they are now
connected with running stitches inside the shape. A single fill or
satin object goes from 3 trims to 1.

Co-Authored-By: Claude <[email protected]>
PlanBuilder runs Design.build_plan on a worker thread with at most one
build in flight; edits made during a build are coalesced into a single
follow-up build with the newest state. The object list and inspector
update immediately, needle list/stats/canvas when the plan arrives.
Export, PDF, PNG, quality doctor and floppy writer wait for the current
plan first. Generator exceptions show in the status bar instead of
crashing the app.

Co-Authored-By: Claude <[email protected]>
…d heatmap

- Auto-digitize: Cancel/Esc/close now stops the worker at the next
  progress point; the plan is computed for the main window's hoop.
- New/Open/Import/Drop/Close ask before discarding unsaved changes.
- Simulator draws only the newly reached stitches onto the cached
  image instead of re-rendering the whole plan every tick
  (demo design: ~108 ms -> ~15 ms per tick).
- Heatmap cell counts are cached per plan version (~28 -> ~12 ms
  per repaint).

Co-Authored-By: Claude <[email protected]>
…-stitches

Every stitch the guard removed from a filled circle sat on the outline:
tatami row turns are ~spacing apart, below the 0.45 mm micro-stitch
limit, so the edge became ragged. Direction changes > 60 degrees are now
always kept; real micro-stitches on straight runs are still filtered.

Co-Authored-By: Claude <[email protected]>
New SatinObject.underlay_style (default 'auto'): <= 2 mm centre walk,
<= 4.5 mm edge walk, wider edge walk + zigzag - like commercial
auto-underlay. Underlay now starts at 1.2 mm column width (was 1.6).
Old projects without the field load with 'auto'.

Co-Authored-By: Claude <[email protected]>
pyembroidery's JEF writer skips TRIM commands unless settings
trims=True, so Janome machines never cut between objects. Trims are
now written as three zero-length jumps (Janome convention).

Co-Authored-By: Claude <[email protected]>
SVG import (engine/pro_tools.py):
- transform= on elements and ancestor groups (matrix/translate/scale/rotate/skewX/skewY, composed)
- path parser: S/T/A (proper endpoint->center arcs), implicit repeats, "1.5.5"/"-1-2",
  compact arc flags; unknown commands end the path instead of desyncing tokens
- style inheritance (fill/stroke/display/visibility/opacity, style= wins), default fill black,
  fill="none", gradient url() -> first stop colour; full CSS colour names, rgb(%), #rgba/#rrggbbaa
- skip defs/clipPath/mask/symbol/marker/pattern/style/metadata; support <use> (+symbol)
- ellipse, line, rounded rect, polyline; fill-rule evenodd/nonzero (winding-based holes)
- thin strokes -> bean run over all subpaths, wide strokes (>=1.2 mm) -> satin band
- target_width_mm=None uses physical width/height/viewBox size

FAT12 (io/fat12.py):
- add_file is transactional (checks space + root slots first, ValueError, image unchanged)
- Windows-style unique short names (NAME~1.EXT) with VFAT long-name entries
- only the last dot of a real extension counts ("Logo v1.5" -> LOGOV15.EXP)
- delete/read accept exact 8.3 names from list_files(), long names still work
- 0-byte files allocate no cluster; cyclic/corrupt FAT chains raise ValueError

Co-Authored-By: Claude <[email protected]>
A crafted SVG with nested <use> references doubles at every level and
would hang the import. The tree walk now stops with a ValueError after
50k visited elements.

Co-Authored-By: Claude <[email protected]>
…) into DE/EN/FR/ES

- dialogs.py: all titles, labels, buttons, combo items, message boxes and
  auto-digitize progress messages (the engine's German messages are mapped
  to keys in the dialog, so the engine is untouched)
- main_window.py: message boxes, status bar, file dialogs/filters, tooltips,
  object-list kind labels, needle list, unsaved-changes and scale dialogs;
  the rail zoom tool now says "fit to hoop" in all four languages
- Inspector: PARAMS labels and list option values translated at display
  time (param_<kind>_<attr> / param_<attr>, opt_<value>); stored data
  values unchanged
- Hoop strategy descriptions, hoop and machine display names translatable;
  Hoop.name / MachineProfile.name stay as stored keys
- PDF production sheet translated
- fmt_int()/fmt_float() replace the hard-coded Swiss separators
- tests/test_i18n_coverage.py: key existence scan, table completeness and
  placeholder consistency, no German text in EN/FR/ES main window,
  inspector and dialogs

Co-Authored-By: Claude <[email protected]>
- 'Optimise colour order' only moves an object forward to an earlier
  block of the same colour when it overlaps none of the objects it
  skips, so stacking order stays visually identical.
- The Melco floppy dialog asks before replacing a file with the same
  8.3 name (two long design names easily map to the same short name).
- ColumnObject (manual satin column: centre line + width) data model;
  the drawing tool is wired up once the column stitch engine lands.

Co-Authored-By: Claude <[email protected]>
- Quality Doctor messages go through tr() in all four languages and
  suggest the OpenStitch Micro font for small lettering.
- Round-hoop collision check and auto hoop selection used the bounding
  box corners, overestimating round designs by up to 41 % (a 64 mm
  circle was reported as 90 mm in a 75 mm hoop). They now use the
  actual needle positions.

Co-Authored-By: Claude <[email protected]>
…umn generator

- engine/column.py: column_runs() - satin column along a centre line with smoothed
  stitch direction, inner-side short stitching, soft mitre / clipped-mitre corner
  handling, centre-walk underlay (>= 1.0 mm), bean fallback (< 0.7 mm)
- fonts_micro.py: "OpenStitch Micro" centre-line glyphs (A-Z, a-z, 0-9, punctuation,
  DE/FR/ES accents), layout, per-glyph travel runs along centre lines and
  stitch-order optimisation that avoids short visible connector stitches
- text.py: builtin:micro listed first in list_fonts(), TextObject lays out and
  stitches micro glyphs (height, letter spacing, arc, transform); TTF path unchanged
- tests/test_micro_font.py

Co-Authored-By: Claude <[email protected]>
Copilot AI balanced review requested due to automatic review settings October 28, 2026 15:31
- Tests for ColumnObject (perpendicular stitches, bounds, save/load).
- Quality Doctor no longer warns about small text set in OpenStitch
  Micro, and falls back to the text when the object has no name.
- Newly drawn objects get translated default names.
- CHANGELOG.md for the upcoming v0.3.0.

Co-Authored-By: Claude <[email protected]>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@lb2002
lb2002 merged commit deb310a into main Oct 28, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants