The canonical, always-current Go API is the godoc on pkg.go.dev/github.com/MarkovWangRR/iso-topology — it is generated from the source and never drifts. The sections below are the hand-written tour.
Go library
Module path:github.com/MarkovWangRR/iso-topology
- Render a DSL document to SVG — Quick example
- Edit a DSL document by applying direct-manipulation ops (drag, set field, add/delete/duplicate) while preserving comments — Editing for embedders
- Introspect the DSL contract —
CapabilityReport()
Quick example
RenderSource is the convenience entry. For finer control (intercept a stage,
render per-part, pick the layout engine) use the pipeline functions in
Public API surface.
Consume the emitted scene
RenderScene(doc) returns a SceneResult with SVG, Routes and
ScreenLabels. Connector records use the contract below. Screen-label records
are collected during the same render, after obstacle placement, using the
emitter’s decimal precision. Collection does not change the SVG bytes or rerun
label placement. This is a partial shared result: isometric body geometry and
top-face budgets still have separate resolvers.
RenderSceneWithInteraction(doc) additionally populates SceneResult.Model
(model, omitted from ordinary renders). Use this entry when displaying an
editable preview. In top projection, resolved footprints, accepted routes,
the coordinate frame and final title/connector-pill arrangement are shared by
SVG emission and the world interaction model. A content arrangement already
certified by route refinement is reused. The isometric interaction model
retains its established resolver. Studio render/edit responses use this
combined entry without changing their HTTP fields.
Reuse is confined to a single request, with no cache keyed by a mutable input
document. Separate calls own their models and nested selection/port slices;
an edited document is resolved anew. BuildInteractionModel(doc) remains
available for geometry-only callers and preserves the fast path for plan
scenes without bound titles. Plain RenderScene does not compute an extra
interaction model.
RenderSceneWithReport(doc) returns both the scene and a RenderReport, sharing
the emitted screen-label records. BuildRenderReport(doc) uses that entry point
when only the report is needed; other diagnostics retain their existing
resolvers and score definitions. Caption repair simulation is requested only
when a reported caption occlusion needs a padding patch. The CLI applies --projection before rendering and diagnostics,
and --report writes labels from the same render as topology.svg.
Each ScreenLabel describes one emitted label in layer order:
PartIDis the emitted instance identity, including any replica suffix. Anonymous labels retain an empty ID.PartIndexis the lowered geometry index, not an authored array index or a stable identifier across edits.Boundsis the submitted transparent pointer rectangle, in final SVG user coordinates before browser viewBox/CSS transforms and live drag. It does not include the chip’s border stroke. Consumers must apply the current label group’s screen transform when working in CSS pixels.FontFamily,FontWeightandFontSizedescribe the emitted font request. A fully bound block hasTextMetrics: "shaped-ink"and aFontHashmatching the embedded resource. ItsLinescontain the emitted text, horizontal anchor, baseline, advance and optional glyphInkBounds. An empty line has zero advance and no ink bounds. Glyph boxes describe geometry, not a visibility mask or a readability guarantee.- An unbound or unsupported block retains
TextMetrics: "estimated-advance". Its legacy single text node is recorded without invented advance, ink or font hash; normal SVG whitespace collapsing still applies. The browser’s actual glyph envelope may exceed the estimated pointer rectangle.
screen_labels; SceneResult emits an authoritative
empty array for an absent isometric screen-label layer, including the top
projection. This does not mean that other text layers are absent. The report
omits screen_labels when empty. Studio’s HTTP responses use screenLabels
and always include the array on a successful render. Separate renders own
their records; the scene and report returned together share the label slice.
Observe content fitting
ContentFits(doc) observes the final top-face content layout after resolving
layout, groups, replicas, style, wrapping and row/column selection. It returns
deterministically ordered ContentFitObservation records without mutating
the input. Path locates the authored part when its ID is unambiguous;
PartID retains the expanded instance ID, and PartIndex is the index after
lowering (not the source array index). Anonymous or ambiguous instances fall
back to the owning node path and do not imply an automatic source patch.
Each record’s Fit has status estimated-fit, estimated-overflow,
unsupported, or empty. Empty observations are omitted from ContentFits.
The fit describes the preferred padding and supported ink-separation budgets
in local face coordinates.
Items contain final text, font size, text/image viewport bounds,
and overflow on the left, top, right and bottom. Manual identifies retained
authored icon placement. A budget violation can mean insufficient padding
even when the content remains inside the physical face. It is not a proof of
glyph clipping, readability, opaque pixels, or correct font fallback.
For top-face labels explicitly using Source Sans Pro at weight 400,
600, or 700, text_metrics: shaped-ink identifies glyph ink bounds from
pure Go shaping of the exact embedded font; font_hash is its SHA-256.
Horizontal Latin/Greek/Cyrillic and supported punctuation/combining marks
are measured as complete runs, including kerning and ligatures. A line with
missing glyphs, unsupported script/control characters, or an unbound font
retains text_metrics: estimated-advance. ProjectedContent.EstimatedText
is true if any emitted text line is estimated. Bounds remain bounding boxes,
not glyph masks; SVG rounding, transforms and raster antialiasing still apply.
The existing fit status names remain conservative and unchanged.
Composite rendering records embedded fonts at their first actual use and
shares each immutable resource across subsequent parts in that render. This
avoids generating a full font payload for every part before removing duplicates.
Resource collection is local to the render; independent and concurrent renders
do not share emission state. Public standalone shape renderers and
Convert2DTo25D still return self-contained SVGs. Resource collection preserves
the first definition’s position, geometry, typography, and serialized output.
For bound-font text, Gaps records unmet separation constraints. Each entry
contains before and after element indexes, kind (text:text or
icon:text), and required, actual, and shortfall distances. Adjacent
visible text lines require a vertical ink gap of 0.12 times their larger font
size; icon/text boxes require at least 4 local units along either axis.
Negative actual means overlap along the measured separation direction.
Shortfalls over 0.01 local units produce estimated-overflow, including when
all items satisfy the outer padding. Image bounds describe the viewport, not
opaque icon pixels. These are local layout preferences, not guarantees of
readability at a particular zoom. Unbound text does not certify ink gaps.
iso25d.ShapeContent(shape, options).Fit exposes the same observation next to
the projected elements; item indexes refer to those elements. Free captions,
spheres and other layouts without a bounded top-face budget remain explicitly
unsupported. The separate top projection has no isometric observations.
Screen-oriented labels are removed before observing their composite part’s
icon-only face layout. Known fully transparent text is omitted from fit items.
Screen-label rendering separately uses bound glyph geometry when the entire
label supports the selected built-in font. It shares that geometry between
text baselines, background, pointer hit rectangle, obstacle reservation and
export bounds, and embeds the same font once per weight. This does not add
screen labels to ContentFits: its public records still describe bounded
top-face budgets. Unknown/mixed fallback labels retain their estimated path.
After placing all screen labels, a bounded compaction pass can move displaced
captions closer to their owners. It retains the chosen side and alignment,
reserves every other label, and checks the serialized rectangle against body,
content, submitted stroke and arrow envelopes. A move must improve the owner’s
box distance by more than one SVG unit and cannot reduce any peer’s relative
association margin (distance to peer minus distance to owner), allowing 0.01
SVG unit for coordinate rounding. It stays inside the prior label/owner
envelope with the same tolerance. The untouched axis retains its original
text anchor, avoiding a one-decimal-step shift from rounded rectangles. This is a
geometric association heuristic, not a proof of semantic clarity.
The pass makes at most four deterministic sweeps. Unknown screen blocks,
unmeasured top-face or connector text, annotations, structural text, face
surface layers and blur/shadow/glow effects retain the established arrangement
until their full envelopes are available. Clean preferred captions keep their
position. Rectangle caching and reusable scratch space bound allocation;
the pass does not rearrange nodes, change routes, resize text or displace a
peer to make room. It is a local refinement, not a global label assignment.
ContentFitIssues(doc) reports estimated overflow as warnings and is included
in Validate. BuildRenderReport adds content_fits and corresponding
content-fit defects without suggesting an unverified automatic patch.
The shared visual candidate guard protects each instance, text/icon kind,
violated side, and indexed gap separately, so reducing one violation cannot
pay for another. Gap indexes describe the final layout’s elements; they are
not stable authored line identities across arbitrary reflow.
These observations are separate from the legacy scalar readability score;
a high score does not clear a reported content-fit defect or certify readability.
Observe connector geometry
RenderWithRouteInfo(scene, theme, canvas, annotations) returns the same SVG
as RenderWithCanvas, plus per-connector records for an isometric composite.
It does not change the input document. Non-composites and the top projection
return no isometric route records.
WorldandScreenretain the existing pre-clip edit/scorecard tracks.World3Dadds the corresponding heights. For Bezier samples, the height interpolates between anchors; this is a declared lifting convention, not a physically solved cable.Drawing.Pointscontains the submitted path after endpoint trimming, clipping and coincident-path reuse, at SVG decimal precision.Kindispolylineorquadratic; the latter has start, control and end points.Drawing.Provenancerecords the source of each submitted segment as the emitter transforms it.SourceSpaceispreclip-polyline(segment indexes intoWorld3D) orpreclip-quadratic(the original analytic curve, segment zero, not the sampledWorld3Dpolyline). It does not index authored waypoints. ForKind: source, final parametertmaps toSource.T0 + t * (Source.T1 - Source.T0)onSource.Segment.Worldcontains two endpoints or three quadratic controls. The curve uses the same linear-height convention as the pre-clip samples.- A provenance segment with
Kind: derivedrecords a new terminal shortcut chord and its inputAncestors; those inputs are ancestry, not an exact parameter mapping.Kind: unresolvedretains ancestry and aReasonbut omits world geometry, for example when coincidence reuse displaces the submitted path. Identical rounded projections retain their own heights. For segments withWorld,ProjectionErrorbounds the difference from the rounded submitted path in SVG user units. It is not a physical routing or pixel-visibility guarantee. SourceRef/TargetRefretain logical endpoints;ResolvedSource/ResolvedTargetretain the attachment references actually used. These may differ for promoted cross-group orthogonal connections.Drawing.Attachments.Source/.Targetmake the endpoint contract explicit: logical reference and instance, resolved reference/instance/anchor, submittedPoint, finalRouteSegmentandRouteT.VisualRuleisfixed-contourorlegacy-silhouette-trim.Worldhas theproducer-route-liftconvention, aknownpoint or anunresolvedstatus with a reason. This world point belongs to the final route, after trimming; it does not certify a physical interface on the owner’s surface. Returned points do not alias the source.PaintBeforePartis the actual insertion position among rendered parts.Arrowis the submitted overlay polygon.Labelrecords the pill rectangle and text anchor, not measured glyph bounds.Drawing.Coveragepartitions each submitted segment by later opaque body fill coverage.OpaquePartslists covering instance IDs in painter order (#part:Nidentifies an unnamed rendered part).UnresolvedPartsrecords uncertain coverage, including unsupported envelopes or materials.
opaque-body-fill-centerline. Empty coverage does
not certify pixel visibility: stroke width, dashed gaps, text, icons,
filters, translucent compositing and later overlays are outside that scope.
Curved body polygons carry BoundaryError in SVG user units, including a
0.03-unit coordinate-rounding allowance. The observation follows the current
painter order; it does not prove that order is physically correct in 3D.
Keep the pre-clip track when editing a route. Drawing.Editable obtains its
source indexes from Drawing.Provenance and excludes overlap with other
submitted segments. Removed pre-clip legs cannot veto an edit. Missing,
derived, unresolved or inconsistent source mappings are not editable.
Provenance alone does not make an overlapped segment visually distinguishable.
The internal depth experiment also records Spatial.SubmittedCollision for
supported polylines and opaque box scenes. Its scope is
submitted-world-centerline, using the producer-route-lift convention:
final source segments and derived chords are tested in their own world
geometry, after clipping and simplification. Segment indexes the final
polyline and T0/T1 bound its interval inside an open box. Face contact and
isolated tangency do not count; entering an endpoint’s own body does count.
Only Status: complete with empty Intervals means no interior occupancy in
the queried boxes. Missing or unsupported provenance is unresolved, never
equivalent to clear. The compositor publishes observations atomically with
the SVG; a legacy fallback omits this report. Historical Spatial.Penetrations
still indexes the pre-clip World3D track, so the two results may differ.
This does not certify physical surface attachments, cable thickness, curves,
or pixel visibility. Fixed contour ports retain their screen attachment and
base-height lift. The experiment remains disabled in public rendering.
Within that experiment, Spatial.Arrow gives a direction marker’s owner,
terminal segment, depth plane and guarded clip region. The convention is
terminal-tangent-billboard: depth follows the last segment’s tangent and is
constant across it. The plane uses coordinates relative to ProjectionOrigin.
Ownership does not exempt the endpoint’s body from occlusion. Emitter-owned
markup offsets associate each arrow with its edge, including identical polygons
at different world heights; the original polygon, alpha and gradient are drawn
once. Missing/degenerate terminal geometry or inconsistent markup makes the
whole experiment fall back atomically. Labels retain their existing overlay
policy. Round stroke caps occupy only their outside half-disks: constant
endpoint depth must not leak back over the sloping segment interior. Surface
antialiasing at mixed-depth interfaces, general body ordering and mixed-shape
locality still require further work before public enablement.
Spatial.Compositing reports how the internal experiment submitted each edge:
painter uses an overlap-constrained primitive order, hybrid retains clips
against the listed LineClipOwners / ArrowClipOwners, and clipped retains
the prior full depth clip with a reason. Uniformly nearer bodies paint over the
primitive once, avoiding the second antialias coverage multiplication from a
complementary clip. Mixed-depth bodies must paint before that primitive and
contribute its local clip. The graph preserves overlapping connector stacking. Body groups are ordered
by their nearest surface depths; projected separation removes unnecessary
constraints. Emitted text/image content retains its established body order
until its full ink and depth are certified. Mixed body depth, a cycle or a work
budget limit retains the prior full clip.
Unverified structural identities instead roll back the entire depth submission.
Drawing.PaintBeforePart and Spatial.Arrow.PaintBeforePart report actual
submitted layers. Internal body groups retain their original data-part
geometry identity and publish a separate data-paint-order. The collector
commits that body order before computing painter coverage; native Studio hit
corridors remain beside their paths in the same DOM order. Full geometric ClipRegion and hit clipping remain distinct
from the local paint clip. The four SVG-unit guard is tested at 0.25/1/4 scales,
not certified for arbitrary device-pixel footprints. This policy is internal and
does not enable depth compositing in public rendering.
Connector export bounds include the actual rounded path’s full round stroke
and arrow polygon, in addition to the established layout margin. Quadratic
bounds use analytic extrema. The extra one SVG-unit guard covers decimal
rounding; it is not a display-pixel antialiasing guarantee at arbitrary scales.
Direct-manipulation editing (for embedders)
This is the contract a cloud service or a WASM client uses to turn a canvas gesture into a new DSL document — the same logic that powers Studio’s drag/edit, exposed as pure, stateless functions:- The transform is a pure function of
(format, src, op)— no server state. (Studio works by POSTing the whole DSL each time; the text is the only source of truth.) - The rewrite preserves the user’s comments and formatting — it is line/regex text surgery, not a reformatting YAML round-trip.
EditOp kinds (the field set read depends on Kind):
move-segment indexes ConnectorRoute.World3D from a render of the same
source. A UI should hit-test Drawing.Editable intervals, which map final
polyline segment parameters back to RouteSegment using the producer’s exact
source record. Curves, ambiguous final projected overlaps and displaced
coincident paths have no edit mapping. These intervals are not proven pixel
visibility: intersect them with the active coverage result and native hit
testing. Studio also checks pointer ambiguity in client coordinates: a
different visible leg within one CSS pixel of the best hit distance prevents
selection, including a visible leg that has no edit mapping. Covered geometry
does not compete in that pointer-distance check.
The operation leaves input unchanged on rejection or a zero effective delta.
It rejects unsupported routes, invalid indices/coordinates, oversized results
and aliased connector mappings. YAML surgery targets the selected scene and
connector, preserving surrounding source and comments; the selected flow
mapping or waypoint field may be reformatted. JSON keeps fields and values,
with normalized indentation. Undo belongs to the caller: record history only
after accepting a valid source and SVG response.
For the lowest level — the individual comment-preserving text operations — import
the yamledit sub-package.
Public API surface
Pipeline (each step is a separate function so you can intercept any stage):isotopo evaluate):
Types worth knowing
Sub-package: yamledit
github.com/MarkovWangRR/iso-topology/yamledit — comment- and
format-preserving text surgery on DSL source. ApplyOp is built on it; import it
directly only if you need a single operation (e.g. just SetField). Every
function takes the source string and returns the edited string, touching only
the lines it must:
SetField, UpsertInlineKey, UpsertInlineList,
FreezeLayoutText, AddPart, DeletePart, DuplicatePart,
FindPartIDLine, FindConnectorLine, FindCanvasLine, ReadPath. Full list
on pkg.go.dev.
Sub-package: iso25d
The low-level iso renderer, if you want geometry without the DSL:
Browser / WASM
The engine compiles forGOOS=js GOARCH=wasm, so RenderSource and
ApplyOp/ApplyOpText can run client-side (zero-latency edit + preview). The
only filesystem touch — inlining a local-file icon — is build-tagged off in the
js build and degrades to passing the reference through, so a wasm build never
fails on a local icon. Inline local icons as data: URIs before handing the DSL
to the module if you need them in the browser.
Measured connector labels
SceneResult.ConnectorLabels and RenderReport.ConnectorLabels use
connector_labels (omitted when empty). Each record has connector_index
and label; the index refers to the scene’s connector array in both iso and
top projections. Only fully bound labels populate this collection. Legacy or
unsupported-font labels are not certified by an absent record. Iso
ConnectorDrawing.Label.Typography references the same submitted geometry;
top still has no iso Routes or ScreenLabels.
label.rect is the final rounded pill box, and label.anchor is its centre,
not a text baseline. Optional typography contains font family/weight/size,
resource hash, final per-line baselines, advances, and ink bounds. Its
placement is clear-within-scope or blocked, with a machine-readable
scope naming body/arrow/pill AABBs and other-route stroke envelopes.
The latter contain real stroke width, round caps/joins and the declared
quadratic approximation error, rather than filling diagonal AABB corners.
An unchanged position’s existing exact curve-bounds certificate is retained
if the new approximation extends beyond those bounds. Own route ink is
intentionally covered by an inline pill. This default scope excludes substrate
content, arbitrary-font ink, effects, and full pixel visibility.
In iso scenes with fully bounded body/content geometry, a still-blocked label
can be refined again without moving any already-clear label. A successful
refinement declares the more specific scope
body-region,content-quad,other-route-stroke-envelope,arrow-aabb,pill-aabb.
It protects separate filled faces, their stroke/curve-error envelopes,
measured text quads and icon viewports, including content outside a body and
on substrates. Substrate fills remain available for labels. Concave faces
retain their notches; a custom path’s convex outline accent is independently
protected as strokes. The 6-unit gap applies to these bounds. This path is
conservative about all submitted faces, irrespective of opacity or occlusion;
it does not claim complete pixel visibility.
The entire extra pass falls back to the previous arrangement if any node
content lacks known metrics, a shape has no supported body envelope, or a
scene contains screen labels, annotations, legacy connector pills, structural
rows/cells, custom face surfaces, backgrounds, blur, shadows, glow, grain or
patterns. Currently supported bodies are box/rectangle/square, cylinder aliases,
circle, person, triangular/hexagonal/octagonal prisms, wedge, cloud and custom
paths; support still depends on the actual content. Person/circle captions and
cloud labels without icons bind the embedded Source Sans Pro resource when
the entire block has supported glyphs and weight (400, 600 or 700). These
captions preserve authored newline boundaries and the requested size
(serialized to two decimals), reserve real ink spacing, and expand the export
frame without moving the body in world coordinates. Their content-fit status
remains unsupported: measurable ink is not a claim that the caption fits a
bounded face or avoids other scene objects. Cloud captions without icons
retain their previous centroid; clouds with icons
retain the existing inscribed face layout and fitting report. Unknown fonts,
weights or partially unsupported blocks retain their previous metrics/path.
Unchanged labels keep their existing scope; a blocked result is
never promoted merely because geometry is unavailable. Top projection retains
its footprint routing path. Fully measured plan node titles are also protected
by their per-line ink AABBs (scope adds plan-title-ink-aabb). Unknown title
metrics retain the conservative joint-placement fallback. This synchronous optional pass has a shared
1,024 support-line/route-segment search-work budget and a 16,384 region-point
storage limit. It first screens for route/pill-only blockage. Reaching a limit
preserves prior positions/status and is not proof that no solution exists;
these deterministic budgets are not a wall-clock latency guarantee.
Coordinates
are root SVG user coordinates before browser transforms. Collection does
not modify the drawing or rerun placement. RenderSceneWithReport adds
connector-label-placement warnings from this same render; existing
Validate and readability scoring retain their separate diagnostics.
Report repair simulations copy connector records, so tentative route upgrades
cannot change the caller’s authored routing or a subsequent render.
After the complete individual placement and eligible body refinement, a bounded
joint pass can arrange still-blocked labels together along their existing routes.
It fixes every already-clear label, offers safe interval-boundary/interior choices,
and compares connected groups with each label’s exact old position as a fallback.
It favors more clear labels, then less movement within its finite candidate set.
An unresolved label never moves; a moved label must clear even its unresolved
peers. Independent components can improve separately. Search exhaustion retains
the best fully checked assignment and is not a proof that the scene is infeasible.
This pass requires reliable body/content bounds: unknown iso content/effects and
legacy pills keep the previous layout. Plan node titles still use ambient font
metrics, so plan scenes containing such titles retain their previous arrangement.
No node, route, arrow, font size or authored text is changed by joint placement.
RenderSceneWithReport also collects typography.conflicts for blocked
measured labels, shared by its returned scene and report. Plain RenderScene
keeps these detailed diagnostics absent so interactive previews do not build
or transfer a potentially quadratic conflict list. Both paths emit the same
SVG, label positions, text and placement status. Candidate repair gates request
the detailed observations on their own render pass; no diagnostic re-layout is
performed.
Each conflict identifies a kind (body, route, arrow, or label). Bodies
carry part_id and a flattened part_index; other counterparts carry the
scene’s connector_index, including zero. Parallel connections remain distinct.
An unnamed body receives #part:<index>. Its clearance_shortfall is in root
SVG units and includes the declared 6-unit gap. For a rectangle it is the
minimum L-infinity translation out of the forbidden centre region. For a
route it is the maximum such penetration over its swept segments/chords;
connected collinear pieces of equal width are coalesced first. This is a
per-primitive envelope severity, not pixel overlap area, hidden route length,
or the minimum move that resolves the union of all conflicts. Body/arrow/pill
bounds retain their existing conservative scope. Own route ink is excluded;
own arrow ink is protected. Legacy peer pills retain an identity without
claiming measured legacy glyph ink. Rich body-region certificates are not
reinterpreted as body-AABB conflicts.
Conflict lists are deterministic and complete within this diagnostic scope;
report warnings name up to three counterparts while the structured list keeps
the rest. Clear labels keep their existing certificates and have no list.
An absent list in a plain preview, an unknown-font label, or an unsupported
scope must not be interpreted as a general visibility guarantee.
Measured connector presence and clear/blocked state also enter the per-edge
scene candidate defects (connector-label-missing / connector-label-blocked).
Already-blocked labels also contribute counterpart keys and measured
clearance shortfalls (connector-label-body, -route, -arrow, -label).
Routing upgrades now reject every new or worsened defect in the existing
per-object/per-edge scene map, including transferred crossings/tunnels and
new blockage or disappearance of a measured label. Existing body-repair gates
consume the same label keys. Aggregate improvement cannot buy a new pair or
increase an already-blocked label’s measured shortfall. Other repair actuators
and unbound fonts retain their existing checks.
Top projection node titles
SceneResult.PlanLabels and RenderReport.PlanLabels (plan_labels, omitted
when empty) describe titles in the submitted plan SVG. Studio render/edit
responses expose the same collection as planLabels. part_index is the
preorder footprint index, including containers and collapsed stacks; records
are returned in paint order. part_id preserves the emitted identity.
An explicit Source Sans Pro family with supported glyphs and static weight
400, 600 or 700 binds the same font for shaping and SVG embedding. The resolved
requested size is preserved to two decimal places. Leaf titles use a centred
budget with 8 units of horizontal and 6 units of vertical inset. Container
titles align left in the band above their first direct child’s footprint,
reserving its outline and a 6-unit gap. Footprints are not resized or moved to
accommodate a title. Automatic plan routes may use the guarded refinement
described below when title translation alone cannot resolve an obstruction.
Wrapping preserves every grapheme, space and authored newline. It prefers
spaces, then permits grapheme-boundary breaks. lines[].source_line identifies
the authored newline index; concatenating that line’s fragments reconstructs
its original text. Width wrapping is accepted only when its block fits the
available height at the requested size. Otherwise the authored lines remain.
The extra wrapping search stops after 65,536 measured input bytes and retains
remaining text; this limit does not cap the initial full-text shaping cost.
Records include the original text, actual SVG font request, resource hash,
budget, per-line baselines/advances/ink bounds and overflow in left, top,
right, bottom order. status: within-budget means ink lies in that title’s
budget; it does not certify whole-scene visibility. overflow retains the full
text and adds a located plan-label-fit warning. Candidate guards preserve
per-part, per-side overflow severity. Export bounds and approximate world
selection regions include all bound ink, including overhangs. Selection adds
0.01 units to cover final SVG anchor rounding after canvas translation.
Unknown families, unsupported weights/scripts, and partially unsupported
blocks retain the original ambient-font SVG path: 11-unit centred leaf titles
and 13-unit, weight-600 container titles. Their records say unmeasured, list
the legacy SVG font request, and omit lines/hash rather than inventing bounds.
An unmeasured result’s zero overflow array does not mean the text fits.
ContentFits remains the separate isometric top-face contract; plan titles
are not added to ScreenLabels or iso Routes. Title-to-title and route-to-title
visibility, arbitrary system fonts, complex scripts, global space allocation,
and target-display-scale readability remain outside this title-fit contract.
Plan route separation
DetailedRenderSceneWithReport results expose plan_route_crowding on both
the scene and report. EvaluatePlan publishes the same observation under
route_crowding. Ordinary previews omit this diagnostic payload. It describes
the final submitted plan paths; the older crossings score keeps its existing
centreline definition and does not count every overlap or insufficient gap.
status: complete with an empty conflicts array establishes clearance only
within the declared scope. Each conflict identifies connector_index,
peer_index, the primitive pairing (stroke-stroke, stroke-arrow,
arrow-stroke, or arrow-arrow), a screen-space bounding rectangle and union
area in squared SVG units. This area measures intersections of clearance
envelopes, not painted overlap pixels. Stroke envelopes contain round caps,
joins, casing and continuous coverage of dash gaps; each route contributes
half the six-unit reading gap. Markers use the emitted triangle and its final
direction. Opaque leaf cores mask hidden regions; transparent/unknown fills
and container fills do not establish occlusion.
Shared endpoints receive only a local neighbourhood exemption, with radius
12 + (widthA + widthB)/2 + 6 in SVG units. Both routes must dock at the same
serialized point on the same node. Long coincident runs and remote crossings
remain observable. Separate edges connecting the same pair of nodes receive
no such exemption, including short or bidirectional parallel edges.
Observations stop explicitly with status: unresolved and a reason when
geometry is non-finite or work limits are exceeded. Limits include 512 points
per route, 8192 scene route primitives, 262144 route pairs, a bounded clipping
work counter, and 256 region pieces per primitive-pair intersection. Partial
conflicts remain available but are not a clearance certificate. Reports add
located plan-route-clearance warnings and, when needed,
plan-route-clearance-unresolved.
After title-driven routing, automatic plan routes may also separate observed
route conflicts without requiring a title obstruction. This phase uses at
most 128 geometric probes and eight complete scene trials. A candidate must
remove a conflict, preserve every other counterpart’s severity and existing
clear text positions, and satisfy the complete stroke/body/arrow/border
guards. Unknown text and legacy pills prevent changes; explicit paths and
fixed contour ports remain protected. Unresolved observations never authorize
a route change. Final export bounds include accepted detours even when the
scene contains no text.
Plan title clearance and local movement
Bound titles additionally publishplacement with a status of
clear-within-scope or blocked, an offset from the preferred layout, and
an explicit scope. Fit status remains independent: a title may fit its own
budget while a route crosses it. Detailed reports include conflicts identified
by counterpart kind, part index/ID or connector index, with the maximum
L-infinity clearance shortfall over its primitives. They use the same six-unit
gap as the final placement predicate. Ordinary previews omit the detailed
conflict list. plan-label-placement warnings locate unresolved titles;
plan-title-blocked and counterpart/severity keys protect subsequent scene
candidates against new or worsened conflicts.
The scope covers later-painted body AABBs, known title ink AABBs, route stroke
and casing envelopes, arrow AABBs and connector pill AABBs. Boundary interiors
remain empty; their dashed borders are conservatively treated as continuous
strips. A fully opaque rounded footprint’s inner rectangular core can hide
older title or route ink according to the actual paint order. Container fills
paint before routes, so they cannot hide a later route. A leaf’s own fill can
hide route ink beneath its internal title. Transparent, unknown CSS fills and
rounded corners outside the proven core never establish that exemption.
The envelopes retain conservative false positives; this is not a per-glyph
pixel visibility or full scene compositing certificate.
The plan content resolver freezes the complete connector-pill arrangement
before trying title moves. Only blocked, fully measured titles that already
fit their budgets may move, by rigid translation inside the same budget.
Text, size, wrapping, nodes, ports and routes stay fixed. Previously clear
titles stay at their exact anchors. A move is accepted only when every title
line clears all protected counterparts, including still-blocked peer titles
and all pills. Clearing a title can improve a fixed pill’s final status; it
cannot move that pill or make a clear pill blocked. Render output, report and
interaction selection all use the resolved placement algorithm.
Any unmeasured nonempty title or legacy connector pill disables automatic title
moves for the scene; known geometry can still be observed. Unresolved titles
retain their original positions and report retained_reason such as
unmeasured-text, infeasible-budget, no-safe-candidate or search-budget.
Search is deterministic: at most 255 boundary hints per axis are reduced to
32 positions each, then at most 512 translations are checked by distance. All
titles share 65,536 line/obstacle predicate checks for candidate verification.
Only fully checked moves commit. These bounds do not cap initial/final
observation or typography work and do not prove that an unexamined feasible
position cannot exist. General visibility, arbitrary fonts and global layout
optimization remain separate work.
Automatic plan routes around unresolved titles
After title translation, a residual route/arrow conflict may trigger a second pass over automatic orthogonal routes. It tries alternative node-side and title-side corridors with a scene-wide limit of 32 candidate evaluations. Only a candidate that clears at least one previously blocked title can commit. The entire resulting title and connector-pill arrangement is observed again; no counterpart may acquire a new conflict or a greater clearance shortfall. Previously clear titles keep their exact anchors. Clear pills on other edges keep their boxes; the changed edge’s own pill may follow its new route but must retain clearance. Typography and node footprints remain fixed. A detour must clear unrelated leaf footprints, including footprints on other height levels, with its complete stroke/casing and a six-unit gap. Other routes, arrows, nonterminal contacts with its own endpoints and self-crossings are also checked. The last leg must fit the marker’s full rear extent, casing and reading gap before its preceding elbow. Arrow bounds are conservative. Congested shared-port hubs may therefore retain the old route rather than accept coincident segments. Unknown nonempty title ink or a legacy connector pill disables the pass. The candidate limit does not cap initial observation, typography, or all work inside one complete content evaluation; it is not a global optimum proof. Explicit straight routes, bends, either waypoint form, elbow requests and legacy named anchors retain the original route. Fixed contour ports support detours that preserve both endpoint coordinates and outward directions. Accepted route ink and arrows enlarge the final export bounds with a 16-unit margin while retaining the coordinate origin used for verification, including fixed-port routes. The input document is not rewritten. Plan rendering, evaluation and interaction use the same deterministic routing algorithm; isometric routing is unchanged by this pass.Isometric route clearance and conservative repair
DetailedRenderSceneWithReport results expose iso_route_crowding in both
SceneResult and RenderReport. Ordinary previews omit the diagnostic; their
SVG and submitted route geometry are identical. The observer consumes Drawing,
including final coordinate/stroke serialization, and the same render’s body paint
order. It does not measure the editable, pre-trim World route as screen ink.
The public painter subtracts later known opaque fill cores, inset by the
provider’s polygon error plus 0.02 SVG units. Earlier fills cannot hide a later
stroke. Arrows remain in the public overlay after body fills. An explicit internal
spatial-render experiment instead uses its own body-depth clip regions; this does
not enable that experiment for public rendering. Non-convex or uncertain opaque
coverage, unsupported curves, invalid geometry and exhausted budgets yield
status: "unresolved" with a reason. Only complete with no conflicts establishes
clearance within the declared scope. Translucent fill accumulation, strokes on
bodies, dash gaps, text, effects and connector-to-connector compositing are outside
that scope; the result is not a pixel visibility certificate.
Visible stroke/triangle regions are expanded by three units per side, giving a
six-unit reading gap with a conservative square envelope. Stroke pairs are
recorded only when their direction cosine magnitude is at least 0.98 and their
connected projected overlap exceeds 12 units. Ordinary transverse stroke
crossings remain outside the public warning. Their pairwise contact areas (and
short parallel contacts) are retained privately as candidate guards: replacing a
long overlap with a new remote X crossing cannot qualify as an improvement, even
when the edges share a node. Arrow contacts are recorded separately.
Conflict records retain connector_index, peer_index, kind, root SVG bounds
and the union area of clearance intersections. Kinds are parallel-stroke,
stroke-arrow, arrow-stroke, and arrow-arrow. Area is not a rendered pixel count.
Shared endpoint masks require the same instance and the same known world and
submitted point, have radius 12 + (widthA + widthB)/2 + 6, and never exempt
parallel semantic edges connecting the same unordered node pair.
Limits are 512 routes, 512 points per route, 65,536 counted stroke/body/clip vertices (arrows separately require three points),
one million clipping work units and 256 intersection pieces per pair/category.
Processing occurs in the common projection frame to avoid numeric cancellation
when translating a diagram. Legacy Readability and EvaluateIso.Crossings
keep their previous meanings; new report warnings are iso-route-clearance and
iso-route-clearance-unresolved.
RepairScene can select xFirst or yFirst for an unconstrained orthogonal
connector implicated in a complete observation. It tries at most eight alternatives
per iteration. Acceptance requires fewer conflict identities, no increase in any
remaining pair’s area or existing per-object visual defect, unchanged terminals,
arrows and label records, non-increasing world length/bends and final screen
length/vertical variation (0.03 serialization tolerance), non-decreasing visible
stroke-ink fraction, no export dimension growth beyond a two-unit integer-bound
rounding tolerance, and non-increasing legacy readability cost. Failed trials
restore the source. Explicit elbow, bend, waypoints, 3-D waypoints and anchor/port
references are preserved; unmeasured screen labels or legacy connector pills stop
this additional repair. Plain render and --no-repair never change source routes.
This bounded local choice does not solve global route allocation or establish
arbitrary-scene absence of visual defects.