Semiotic's annotation story started from a structural claim: annotations should be data-bound objects, not artwork pasted on after the chart is finished. That part has been true for a long time. Now, annotations have moved from representation to design assistance. The library now helps answer two questions authors usually answer by hand: which annotation should lead, and where should the note land?
The work is intentionally additive. Existing annotation arrays render as before. Authors opt into hierarchy with emphasis, opt into placement withautoPlaceAnnotations, and can still take over with manual offsets orsvgAnnotationRules.
Hierarchy is part of rendering
A chart with several notes needs a reading order. Now you can addemphasis: "primary" | "secondary" to individual annotations, reusing the same token Semiotic already uses for chart hierarchy. A primary annotation renders at full weight and later z-order; a secondary one dims and yields. When no explicit emphasis is present but annotations carry provenance.confidence, the renderer can infer a subtle order from confidence descending, then authored array order.
Makes annotation hierarchy explicit: the primary note leads, the secondary note stays available without competing for attention.
The important part is where this happens. Hierarchy is not a special case inside one annotation type. It runs through the shared annotation pass, so default rules, custom SVG rules, streaming overlays, and static SVG output all get the same wrapper. The accessibility audit now credits charts that declare hierarchy and warns when several annotations have no reading-order signal.
annotations={[ { type: "callout", pointId: "B", label: "Useful context", emphasis: "secondary" }, { type: "callout", pointId: "F", label: "Main claim", emphasis: "primary" } ]}Placement becomes a recipe
Manual dx/dy is still the floor, but it is not enough when labels move with filtered, sorted, streamed, or resized data. Now Semiotic has an opt-in placement pass for note-like annotations. It estimates note bounds, tries adjacent candidate offsets, penalizes overlap with already placed notes and point marks, penalizes plot-edge overflow, and preserves manual offsets by default.
Keep authored offsets fixed, then choose offsets for the remaining note-like annotations based on nearby marks, existing notes, and plot edges.
The public switch is autoPlaceAnnotations. Pass true for defaults, or an object to tune the recipe. The pure function is also exported fromsemiotic/recipes as annotationLayout, so authors can run the geometry pass themselves and still use their own rendering layer.
import { annotationLayout } from "semiotic/recipes" <Scatterplot data={data} xAccessor="x" yAccessor="y" autoPlaceAnnotations={{ defaultOffset: 40, notePadding: 10, routeLongConnectors: true, connectorThreshold: 55, }} annotations={[ { type: "label", pointId: "edge", label: "Edge note" }, { type: "label", pointId: "center", label: "Center A" }, { type: "label", pointId: "center", label: "Center B" }, { type: "label", pointId: "manual", label: "Manual", dx: 30, dy: -24 }, ]} />Connectors only get louder when they need to
Placement and connector routing are linked. Semiotic does not turn every connector into a swoop. Short, nearby connectors stay quiet. When the placement pass has to route a note farther away, it can set a curved connector so the association remains legible without requiring the author to hand-route the line.
What is deliberately constrained
This is not a magic label engine, and it is not the new default yet. The shipped layout is deterministic and greedy, which makes it SSR-safe and testable, but it is still an estimate of rendered note geometry. The visual regression fixture covers the overlapping-label path before the behavior graduates from opt-in. Authors who need exact control still setdx/dy, disable manual-offset preservation, or replace the rendering pass with svgAnnotationRules.
Why these two milestones belong together
Hierarchy and placement solve different parts of the same production problem. Hierarchy says which note should be read first. Placement keeps that note close enough to its target that the association is legible. The combination moves Semiotic closer to the annotation strategy's larger goal: charts whose communicative layer is engineered with the same care as their marks.