Hand test against an AutoCAD capture: the 0.50mm road edge is ~10px
there but only ~4px here. Lineweight is zoom-independent screen pixels,
so the two captures compare directly - the 8 px/mm mapping was 2.5x too
small. AutoCAD's default display scale is one pixel per 0.05mm, so use
20 px/mm (0.35mm = 7px, 0.50mm = 10px, 2.11mm = 42px) and raise the
clamp to 48px.
Add setLineweightScale()/getLineweightScale() so a host can retune it -
AutoCAD exposes the same thing as the Adjust Display Scale slider.
Re-measured headless: the 0.35mm road-gutter line now renders ~7px, so
both weight classes land on the same scale.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The deployed site serves a .wasm with acadrust compiled into it, and our
vendored copy carries one modified MPL file
(src/io/dwg/dwg_stream_readers/object_reader/entities.rs, the read_mesh
array-count bounds fix). That is Executable Form distribution of modified
Covered Software, so MPL-2.0 3.2 requires the Source Code Form to be
available and recipients to be told how to get it. Nothing shipped said
so: no license text, no notice, no obtainable source - the upstream
mirror repos are private.
Add THIRD-PARTY-NOTICES.md plus public/licenses/ (MPL-2.0 text, the
read_mesh patch against the pristine 0.4.1 crate, and a served copy of
the notice), and link them from the page so recipients can actually find
them. Original crate download plus the patch reproduces the exact source
compiled into the wasm.
MPL does not require upstreaming, and the lineweight work did not touch
any MPL file - dwg-wasm/src/lib.rs is our MIT wrapper. docs/license-mpl2-
acadrust.md records the analysis and the checklist for future changes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every line was drawn 1px regardless of its CAD lineweight. Two causes:
the dwg-wasm parseResult never carried the field (acadrust reads
EntityCommon::line_weight but it was dropped in serialization), and the
renderer merged all segments into one LineSegments whose
LineBasicMaterial.linewidth WebGL ignores.
Resolve ByLayer/ByBlock/Default per entity and bucket segments by
dash|lineweight. Weighted buckets get their own LineSegments2 +
LineMaterial with worldUnits:false, so width stays constant in pixels
while zooming - AutoCAD LWDISPLAY semantics - at 8 px/mm (0.25mm = 2px).
Anything at or below the 0.25mm default stays in the hairline batch so
drawings that never assigned a weight render exactly as before.
Fat batches are instanced, so layer masking compacts the instance buffer
and lowers instanceCount instead of rewriting an index; slotOf tracks
where each segment moved so the selection highlight still finds its
vertices. Per-entity color spans (meta.spans) let the highlight repaint
across the hairline batch and every bucket it touched. Buckets past
400k segments fall back to hairline to bound GPU/heap cost.
Display follows the drawing's LWDISPLAY and can be forced from the
toolbar; the property panel now shows the entity lineweight.
Verified headless at a fixed camera on the 65k-entity road drawing:
cyan road edge 2px -> 5px, layer hide/restore returns the exact baseline
pixel counts, and a 0.35mm LWPOLYLINE selects and highlights.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The road-surface drawing (대산당진 2공구_노면) rendered nothing for its
노면/부체도로면 geometry. The cause was not the renderer: the parseResult
contained zero MESH entities.
Two faults, both in the wasm parser, fixed upstream in hmwebviewer 35f5b1c:
1. dwg-wasm never serialized MESH. acadrust reads the entity in full; only the
JSON arm was missing.
2. acadrust's read_mesh clamped its array counts with the blanket 100_000-item
corrupt-data guard. This drawing's road mesh has 105_497 vertices, so the
count was truncated, the remaining vertex bits were never consumed, and the
face/edge/crease lists after them decoded from the wrong bit offset —
producing a plausible-looking vertex count next to a nonsense 14-face list.
Counts are now bounded by the bits actually left in the object stream.
before verts=100000 faces=14 face sizes [64, 0, 64, 23, 0, 0, 0, 15]
after verts=105497 faces=185444 face sizes [3, 3, 3, ...]
This commit carries the vendored side of that work:
- the rebuilt wasm, which now emits MESH as flat arrays (vertices [x,y,z,...],
faceList in DXF group-93 layout, deduplicated edges). The sample drawing goes
from 116 MB to 130 MB of parseResult with parse time unchanged at ~3.2 s.
- a MESH case in the property inspector (vertex/face/edge counts, subdivision
level, bbox and elevation range)
- docs/subdmesh-rendering.md, plus README pointers
- the acadrust licence notice, which can no longer say "consumed unmodified" —
read_mesh now carries a local patch. MPL-2.0 is file-level copyleft, so the
patched file stays under MPL and its source ships in hmwebviewer.
Verified: 9 MESH entities parsed from the drawing; entity histograms over six
other sample drawings are byte-identical to the previous wasm, so nothing else
moved.
Two deliberate omissions, both because a lineweight/fat-line refactor is in
flight in this working tree:
- Viewer2D.js is not included. Its _meshSegs helper and three MESH dispatch
sites share hunks with that refactor and cannot be separated; the same
renderer code is committed upstream in hmwebviewer 35f5b1c and will land here
with the refactor. docs/subdmesh-rendering.md records this.
- dist2/ is not rebuilt here. The current build embeds the half-wired
lineweight button and progress-bar markup; deploy per
docs/deploy-dist2-static-build.md once that work lands.
The wasm binary also carries the new lineweight parser fields (lwdisplay,
celweight, layer and entity lineWeight), since it was built from a tree that
already had them. They are additive JSON keys with no consumer in this commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This repository has no deploy script or CI: package.json only builds to
dist/ (gitignored), yet dist2/ is committed and is what actually gets
served. The procedure was folklore reconstructed from commit history each
time someone deployed.
Write it down, including the two traps found while deploying fb8f7ca:
- vite's emptyOutDir defaults to true when outDir sits inside the project
root, so a bare `vite build --outDir dist2` deletes the hand-placed test
assets in dist2/samples (configBak/, dwg_18.3mb.dwg). Always pass
--emptyOutDir false.
- npx vite can fail here with `Missing script: "vite"`; call
./node_modules/.bin/vite directly.
Also notes the open issues: no build:dist2 script, old hashed bundles
accumulating in dist2/assets, and test fixtures living inside the build
output directory.
Link it from the README issue table.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Mirrors hmwebviewer's rust/dwg-wasm change into the sample: the wasm
artifact plus the parser wrapper, which now goes through parse_dwg_json
and JSON.parse instead of the JsValue-returning parse_dwg.
Building the whole result as a serde_json::Value tree pushed the live
wasm heap near 2.9GB for a 19MB drawing, and the allocator's cost grows
with that heap, so parsing went quadratic — 354s, with the tab frozen
throughout. Streaming one entity at a time keeps it linear: 2.5s.
The same build also fixes three bugs that drew stray 4km grey shapes
where two CF-PATT SOLID hatches should be. Max hatch span 4655 -> 110.
Adds two docs recording both investigations, in the format of the
existing ones: measurements, the hypotheses that were ruled out, the
fixes, regression checks, and the MPL-2.0 position (acadrust is
unmodified, so no new source-disclosure obligation arises).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>