- a_faces_seam_stays_within_half_its_width_of_the_face checks Rotate
(Classic)'s branches too: No Shading keeps its paint, a gradient keeps
the gradient, and Diffuse shades its plane darker at some view.
- classic_revolves_seams_are_round checks each seam's reach as well as
its join, and covers a gradient.
- The Wireframe edge takes seam_stroke (the same stroke it built by hand).
- Docs: which seams went from miter to round and which already were;
the white-light difference from the 2026-10-17 comparison is expected,
not measured; the 3D area rows record the change; the performance note
says its measurement predates the Classic Rotate and Revolve paths.
Each 3D facet is stroked with a narrow seam of its own paint (0.05 to
0.75 pt; Revolve's is always 0.75 pt) so neighboring facets meet without
an antialiasing hairline. In Extrude & Bevel, Inflate and Rotate under a
white light, and in every face of the 3D (Classic) effects (Extrude &
Bevel, Rotate and Revolve (Classic); shaded, No Shading, gradient and
pattern alike), that seam kept the default Miter Join with its limit
of 10. Revolve's seams and the colored-light seams
were already round. A facet seen almost edge-on is a sharp sliver, and
its mitered seam reached up to ten times its half-width past the facet's
tip: thorns of up to 3.75 pt past the solid, along the tops of type seen
tilted and at every edge-on bevel facet.
#2706 (multiple lights) deliberately kept white-light seam joins as they
were, so that legacy white-light output stayed byte-identical to main
(its comment "Preserve existing white-light paints, alpha composition and
seam joins exactly", and four PNGs compared byte for byte). That kept
the thorns too. This change reverses that one part on purpose: the
paints and alpha composition stay exactly as #2706 left them; only the
join changes.
- Outputs change, the document model doesn't. Exports draw the new
joins (SVG writes stroke-linejoin="round", PDF and .ai draw round
joins), and Expand Appearance writes round seams into the document.
But nothing a document stores selects the join, and the format is
unchanged, so there is no version gate: an old file drawn now simply
has no thorns.
- Round joins. Projected facets rarely have right-angle corners (a
square seen at an angle is a parallelogram with acute corners, and an
exact 90° corner sits at a √2 limit), and round is what the seams of
colored lights and Revolve already draw. The cost: where a facet has
no neighbor (Rotate's plane, every silhouette corner) its convex
corners are drawn rounded by up to 0.375 pt instead of sharp.
Alternatives weighed and not taken: a Miter Join with a limit near √2
at every seam, the composed clip included, which would bevel slivers
but chamfer most projected corners as well; and seaming only the edges
facets share, or clipping facets to their union as solid_surface
does, which would keep every outer corner sharp but means a new
geometry pass for every 3D effect. Round is the smallest change that
matches the seams already drawn.
- A seam no longer reaches past its facet by more than half its width,
so the art's visual bounds shrink by up to 3.375 pt where a thorn
stood (10 × 0.375 less the 0.375 a round seam still reaches).
White-light output is no longer byte-identical to #2706's comparison;
docs/3d-lighting-performance.md says so.
Every seam stroke is made by lighting::seam_stroke. The colored clip in
composed_art already outlined its seam with round joins and is
unchanged. Tests: every seam of Extrude & Bevel, Extrude & Bevel (Classic, each
branch), Rotate (Classic), Inflate and Rotate, under white and colored
light, has round joins and reaches no more than half its width past its
face, at views that make a sliver; Revolve (Classic)'s seams are round
on each surface; a mitered seam fails them, and so does the legacy
white-light Inflate test, which now expects Round.
Add opaque RGB light color and up to ten independently adjustable lights to
Revolve, Extrude & Bevel, Inflate and Rotate. Keep light selection, Add/Delete,
selected-light gizmos and preview transactions on the existing command path.
Preserve legacy white-light Inflate polygons, paint composition and seam joins,
including the 0.05 seam minimum. Use shared smooth normals for colored Inflate,
and batch solid-fill RGB channel paths behind one surface clip. Keep source
paths editable and SVG/PDF output vector artwork.
Rebase onto main f7de3d6a, retaining both sides of progress docs and all 22
catalogs. Shade freeform points once through the shared paint mapper. Document
release measurements and a reproducible CLI fixture, including the remaining
source-gradient cost and the one-light timing tradeoff.
Validation: full cargo xtask ci passed all 10 steps; 7,978 tests passed, zero
failed and 11 ignored. Four legacy white-light PNGs match unchanged main byte
for byte. Three paired release bench/perf repetitions completed without busy
warnings; all six standard perf runs passed every budget. Two-light solid
Inflate improved from 136.2 to 96.8 ms/frame at 1200x1200, default eight threads.