Serve generated SVG drawings in the app - #142
Open
kamilpajak wants to merge 23 commits into
Open
kamilpajak wants to merge 23 commits into
kamilpajak wants to merge 23 commits into
Conversation
catalog/integrate.py now sets hardwareType (derived from the manifest family) when it creates a brand-new image-mapping entry, and rejects families it cannot classify. scripts/catalog-repoint-standards.mjs performs the surgical standards-generated.ts update the README prescribes: it repoints or inserts only the image field for shipped standards covered by the manifest, since pnpm standards:build cannot be used without the local dinmedia cache.
resolveImageWithSvgPriority returned image: null for svg sources, so label-exporter and label-preview skipped the aspect-ratio calculation and the constraint solver sized the image slot from a default ratio. Svg standard images are now loaded and cached like the png path, which becomes load-bearing once standards point directly at generated svgs.
Integrate all 247 manifest keys: copy the 125 generated svgs into static/images/standards/ (refreshing the six stale washer pilots), repoint data/image-mappings.json, and update the image field for the 109 shipped standards covered by the manifest. Five standards gain an illustration for the first time: iso4026-iso4029 (din913-din916 set screws) and iso14579. The remaining 52 shipped png images have no generated drawing yet.
Review follow-up: the codemod depends on the generated file's exact formatting, so it now fails loudly when the header or entry pattern changes instead of silently editing nothing. Also documents that FAMILY_TO_HARDWARE_TYPE is a deliberate whitelist.
The white tile behind dropdown thumbnails exists for the legacy rasters (black drawings that would vanish on the dark theme). Vector drawings have a transparent background and black strokes, so they render on the dark list directly with a css invert filter for light strokes; png thumbnails keep the white tile.
The label printer prints pure black only and drops very thin lines: the drawing lands in an ~8mm slot at 360dpi, where the previous 0.4mm outline was 1-2 dots and the gray dashed hidden lines dithered away. All layers now print black with weights 0.8/0.6/0.4mm, keeping hidden edges and centerlines distinguishable by dash pattern and weight alone. All 125 drawings regenerated.
Eight shipped standards without a manifest key of their own (iso8678, din562, iso7090, iso12474, iso14583, iso4162, iso15071, iso15072) inherited another standard's png through a designation cross-reference, so they kept rendering rasters after the svg integration. The repoint script now swaps such a png for the same standard's svg in a second pass - a like-for-like upgrade, no new equivalence claim. 117 shipped standards render vector drawings.
integrate.py repoints data/image-mappings.json at the generated svgs, so /dev/asset-compare was reading the same svg into both panes. The legacy column now reads data/legacy-image-mappings.json, a frozen snapshot of the mapping as it shipped before vectorization, and each card carries a live badge when the app already serves that drawing.
…imetres Every drawing is scaled into the same small image slot on the label, but the drawings span 20mm to 133mm in their own coordinates, so a constant width in drawing units reached the paper anywhere between 0.8 and 4.1 dots at 360dpi - 59 of 125 below the 2-dot floor where a thermal head starts dropping lines. Drawing standards treat line width as an absolute width on the finished output chosen for the format, the way CAD plots lineweights in paper space regardless of viewport scale. Weights are now derived per drawing from the target printed width (3 dots for the outline, 2 for hidden edges and centerlines) through the drawing's own extent, so all 125 measure exactly 3.00 and 2.00 dots. The dash patterns move to dots as well: the exporter's ISO pattern is built for a full-size sheet and leaves one or two marks per edge at label size, and it offers no hook for a custom pattern, so the two dashed layers are rewritten in the written file.
…size The 3-dot outline printed reliably but swallowed the drawing: at the ~128 dots a drawing gets on the label, a socket head or a washer chamfer merged into a blob. Both layers now sit on 2 dots, the practical minimum for a solid line on a maintained thermal head, and the layers stay apart by dash pattern rather than weight. Centerlines are kept: they are what makes the drawing read as an engineering drawing rather than an icon.
A chain line crossing the whole drawing is the densest layer at label size and was competing with the outline for attention. Centerlines carry no geometry, only the symmetry reading, so they drop to 1.5 dots while the outline and hidden edges stay on the 2-dot print floor.
The whole box is scaled into a fixed slot on the label, so the 2mm margin came straight out of the drawing's own size: geometry filled only 72-88% of the box, against 99-100% for the legacy rasters it replaces. Spacing around the image belongs to whoever places it, and the label's constraint solver already keeps the image clear of the text. Geometry now fills 86-93%, the rest being the centerline overhang, and the exporter still pads by half a line width so the outer stroke is not clipped.
Back to the absolute 0.4/0.3/0.2mm the families were drawn and reviewed with, dropping the printed-dot normalisation and the shortened dash patterns: the uniform 2-dot line was reliable on paper but cost visible detail at the size a drawing gets on a label. This is the starting point for print testing; the research and the measurements behind the alternative are kept in catalog/README.md so the next adjustment starts from data rather than theory. Two changes from the original are kept deliberately: all layers stay pure black, since the label printer cannot reproduce the gray the hidden layer used, and the view box still hugs the drawing.
ISO 128 wants a chain line to begin and end with a long dash, and a stroke-dasharray cannot promise that: the pattern runs until the line stops, wherever that falls. Some arms ended in a gap, so the axis faded out short of its tip and the image carried an empty band up to 1.3mm wide, the view box following the geometry that does reach the tip. The chain is now emitted as geometry. Each arm keeps its exact length, so the overhang past the outline stays consistent, and the pattern is stretched by up to half a period to land on it - what a drafter does with the linetype scale, and imperceptible over these lengths. An arm too short for one long dash becomes a single stroke. The exporter's CENTER proportions are kept, so the drawings look unchanged; the empty band is down to a 0.1mm median with all 125 under 0.3mm.
First tuning step from print testing: outline 0.5mm, hidden edges 0.4mm, centerlines 0.3mm. The chain-line rhythm is decoupled from the pen in the same change. The exporter derives dash lengths from the line width, which is right for a full-size sheet where the width is chosen once per drawing group, but here the width is a printer setting being tuned: at 0.3mm the long dash became 9.5mm, longer than a small drawing's whole arm, and 69 of 125 axes collapsed into a solid line that reads as an edge. The pattern is now fixed in millimetres at what the 0.2mm drawings had, so only the pen changes - 8 of 125 axes are a single stroke, exactly as before.
Widths were fixed in drawing units while every drawing is scaled into the same small slot on the label, so the same 0.5mm reached the paper anywhere between 0.5 and 3.1 dots depending on how large the part is drawn. The widths are now a target on the paper - 1.5 dots outline, 1.2 hidden, 0.9 centerline - converted back into drawing units per drawing through its own extent. They keep the 5:4:3 ratio of the 0.5/0.4/0.3mm they replace and sit on what that scheme printed at the median drawing, so the average weight is unchanged and only the spread is gone. Dash patterns follow. Hidden lines get it for free, the exporter deriving the dash from the now-proportional weight, landing on a constant 14.4 dots. Centerlines carry their pattern in dots as well: tying it to the pen instead had collapsed 69 of 125 axes into a solid line when the weight was last raised.
Every projected edge was sampled at 72 segments regardless of shape, because the sampler cannot tell a line from an arc. A hex outline therefore stored each of its six straight sides as 73 points: 904 of the 942 paths in din472.svg were perfectly straight, and the 125 drawings totalled 14.47MB against 0.77MB for the 181 rasters they replace. The standard picker renders one img per standard with no lazy loading, so opening it fetched all of them at once. Sampled points are now simplified back down with Ramer-Douglas-Peucker at a tolerance of 1/2000 of the drawing extent - about a twelfth of a printer dot at label size - and coordinates are written to 3 decimals instead of 4. The drawings total 1.33MB (0.24MB gzipped), the largest falling from 1.15MB to 70KB. Rasterised at label size and at preview size the change moves 1% of ink pixels, all of them single boundary pixels; the thumbnails also load lazily now.
The widths were solved against LABEL_SLOT_MM = 9.15, a number measured off the ink of a rendered drawing rather than off the slot the app actually gives it. calculateOptimalImageSize() hands a drawing 11.4 x 10mm on the default 12x35mm label, so every line printed about 25% over target. The slot is also not square and the app fits contain-style, while the weights were solved from the drawing's longer side alone, so a portrait and a landscape drawing differed by half again on the same label: the measured spread across the catalogue was 1.31 to 2.09 dots. Weights now solve against min(slotW/w, slotH/h) with the reference slot spelled out from the solver's own formula, and every drawing prints 1.50 dots on that label. Longer labels widen the slot, so drawings reproduced there are larger and their lines proportionally thicker - uniformity is a promise across drawings at one label size, not across label sizes. _chain_dashes only collapses an arm to a solid stroke when it is shorter than one long dash. Rounding the repeat count without a floor collapsed arms up to 1.8 long dashes too, drawing 338 of 750 axes as a continuous line, which reads as an edge rather than an axis; 8 remain solid. The tests now state the reference slot from the solver's formula instead of re-deriving the renderer's own model, cover a portrait and a landscape drawing that bind on opposite axes, and bound the longest centerline segment by the fitter's worst-case stretch rather than by a tolerance wide enough to hide a collapsed arm.
…r nothing The repoint script bridged by filename: any legacy png whose name collided with a manifest key was swapped for that drawing, so two approximations were adopted without anyone deciding to - iso14583 draws a hexalobular drive as a cross recess, din562 draws a thin square nut at full height. Both were already what the raster showed, so neither is a new claim, but they are now an explicit allowlist with the compromise written next to each entry instead of a rule that catches whatever it happens to catch. The script also writes the bridges into image-mappings.json, which integrate.py cannot do because those ids are not manifest keys. Left alone the two files disagreed for exactly those two standards, and regenerating the dataset from the mappings would have silently undone them; the script now fails if any standard disagrees between the two. integrate.py resolves every standard before touching the filesystem and replaces the mappings through a temporary file. Checking inside the copy loop meant a manifest with an unmapped family left the drawings before it already copied while the mappings were never written.
…yout change The live badge read data/image-mappings.json, which integrate.py repoints for every manifest key the moment the SVG is copied, so all 247 items carried it and it said nothing. More than half of those keys are not ids the app knows either - the DIN and ISO forms of one fastener are a single shipped standard, so din931 rides along inside iso4014. The badge now comes from the shipped dataset and marks 98 of the 125 drawings; the 27 without it are shipped but never reach a user. The changelog also records that 25 standards changed label layout: the new drawings are less wide than the pictures they replace, so they fall under the aspect ratio that puts the image in a full-width band and now sit beside the text instead.
The Unreleased entry duplicated what shipped as 3.1.0, so the Fixed section is dropped here and only the drawing changes stay unreleased. Recounted while resolving: 21 standards gain a first illustration, not 5, and 26 labels lose the full-width band layout rather than gaining it.
The line widths were seeded from what the old fixed-millimetre scheme printed at the median drawing, with a note to tune them from real output. A calibration strip carrying din125, din127, din316, din7991 and din936 at 1.5, 2.0, 2.5 and 3.0 dots settled it: the first two are too thin to hold every line on a 360dpi label printer, both 2.5 and 3.0 print clean. 2.5 wins the tie because ink costs detail. Rasterised into the 11.4x10mm slot, going from 2.5 to 3.0 dots closes 5.9% of the white enclosed by the outlines (24582 to 23121 px across the five drawings) and adds 17% ink, for nothing the printer could not already reproduce. The three weights move together, so the 5:4:3 ratio between visible, hidden and centre lines is unchanged. Every drawing still prints at the same width as every other: verified at 2.50 dots across the catalog. catalog/qa/ gains the two scripts that build the strip, so the next calibration does not start from scratch.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Feature: the label generator now renders the generated vector drawings instead of the legacy raster images for every standard covered by the catalog.
How it works today / problem
din_125.svgfrom the mapping value, but catalog files are nameddin125.svg. Zero hits, all raster.data/image-mappings.jsonis build-time input only; the shipped dataset is the committedsrc/lib/data/standards-generated.ts, so repointing the mappings alone changes nothing in the UI.Goal
Show the SVG drawings in the app now: crisper labels at print DPI, and first-time illustrations for standards that never had a raster image.
How
catalog/integrate.pycopies all manifest SVGs intostatic/images/standards/and repointsdata/image-mappings.json(228 repointed, 19 new entries; new entries gethardwareTypederived from the manifest family).scripts/catalog-repoint-standards.mjsdoes the surgicalstandards-generated.tsupdate the catalog README prescribes: it edits only theimagefield for shipped standards that are manifest keys. Result: 109 shipped standards point at SVGs (104 repointed, 5 first-time: ISO 4026-4029, ISO 14579).resolveImageWithSvgPrioritynow loads.svgstandard images instead of returningimage: null. Without this, the exporter and preview skip the aspect-ratio measurement and the layout solver mis-sizes the image slot.static/are refreshed (their hashes had drifted fromcatalog/out/).Test plan
.svgload and failureintegrate.pytests) passes in the pinned containerpnpm check,pnpm lint,pnpm validate-imagescleanOut of scope
din562is shipped); each needs a per-key visual-equivalence checkAVAILABLE_SVGS)