Import these from @grafloria/engine.
On their own pages
DetachedParentAnchor: The LAST-KNOWN ANCHOR of a node the diagram has REMOVED.DiagramEntityDiagramModelGroupModelLinkModelNodeModelPortModelSerializedDiagramSerializedPortStrokeModel: A freehand ink stroke: an ordered point list, a style, and an identity.
Functions
bumpMutationEpoch
Bump the epoch by hand, for a mutation that legitimately bypasses
markDirty() (in-place points rewrites, say). Prefer markDirty().
tsfunction bumpMutationEpoch(): number
distanceToSegment
Distance from p to the segment a→b. The primitive both hit-tests are built on.
tsfunction distanceToSegment(p: Point, a: Point, b: Point): number
getMutationEpoch
Read the current mutation epoch. Cheap enough to call every frame.
tsfunction getMutationEpoch(): number
hasPressure
True when the device gave us pressure worth keeping (i.e. it actually varies).
tsfunction hasPressure(points: readonly StrokePoint[]): boolean
linkLabelPosition
The position along the path (0-1) a label resolves to.
slot WINS over position. Naming a slot is an explicit act; position is a
required field that most slot users only fill in to satisfy the type, so
letting it win would make slot silently do nothing.
tsfunction linkLabelPosition(
label: Pick<LinkLabel, 'position' | 'slot'>
): number
segmentDistance
Minimum distance between two SEGMENTS.
The eraser needs this and a point-test cannot replace it. A pointermove at 60Hz over a fast flick lands samples 80px apart; testing only the sample POINTS lets the eraser jump clean over a stroke it visibly swept through. So the eraser tests the segment it travelled, not the points it happened to land on.
tsfunction segmentDistance(a1: Point, a2: Point, b1: Point, b2: Point): number
Constants
DEFAULT_GROUP_HEADER_HEIGHT
tsconst DEFAULT_GROUP_HEADER_HEIGHT: 24
DEFAULT_GROUP_PADDING
Defaults for groups AUTHORED in code (constructor path). A fitted frame needs breathing room and a title band or its label lands under the first member. Loaded documents are exempt: restore assigns the stored values (padding verbatim — possibly undefined, which getPadding() resolves to 0 — and headerHeight number-or-0), so legacy geometry is byte-stable.
tsconst DEFAULT_GROUP_PADDING: 16
DEFAULT_PORT_SNAP_RADIUS
How near a port must be to a point for {@link DiagramModel.findNearestPort} to consider it, in world units. Roughly a fingertip at 100% zoom.
tsconst DEFAULT_PORT_SNAP_RADIUS: 24
DEFAULT_SIMPLIFY_EPSILON
Douglas-Peucker tolerance, in WORLD units.
0.6 is tuned against real traces: below ~0.4 you keep the sensor jitter you were trying to remove; above ~1.2 a deliberate small loop (the dot of an "i", a tick) starts to visibly flatten. At 0.6 a 500-point scribble lands around 40-70 points and is indistinguishable from the raw trace at 100% zoom.
It is world-space, so ink drawn while zoomed OUT is simplified more aggressively in screen terms — which is right: you cannot see detail you did not draw.
tsconst DEFAULT_SIMPLIFY_EPSILON: 0.6
DEFAULT_STROKE_STYLE
tsconst DEFAULT_STROKE_STYLE: StrokeStyle
LINK_LABEL_SLOT_POSITIONS
Where each of the three edge label SLOTS sits along the path.
Pulled IN from the endpoints on purpose: at exactly 0 and 1 a slot label would land under the arrowhead and on top of the port. 0.12 / 0.88 clears both while still reading as "at the start / at the end of this edge".
ONE definition, shared by the model (LinkModel.addLabel), the renderer (LabelRenderer) and the edge optimizer — three places that must never disagree about where a label actually is.
tsconst LINK_LABEL_SLOT_POSITIONS: Record<'start' | 'center' | 'end', number>
Interfaces
ChangeEntry
tsinterface ChangeEntry
Properties
| Name | Type | Default | Description |
|---|---|---|---|
timestamp | number | ||
property | string | ||
oldValue | any | ||
newValue | any |
CollapsedState
The reversible snapshot captured when a group collapses. Stored (serialized) on the group so a collapsed diagram round-trips and can be expanded losslessly after a save/load — not just within one session.
tsinterface CollapsedState
Properties
| Name | Type | Default | Description |
|---|---|---|---|
proxyNodeId | string | The hidden placeholder node that presents the group as a node endpoint. | |
savedGeometry? | { position: { x: number; y: number }; size?: { width: number; height: number; depth: number }; bounds?: G... | The group's exact geometry before it shrank (restored verbatim on expand). | |
savedPositions | Record<string, { x: number; y: number }> | Member (node) world positions at collapse time (restored on expand). | |
hiddenNodes | Array<{ nodeId: string; prevVisible: boolean }> | Members whose visibility we toggled, with their prior visible value. | |
removedLinks | any[] | Serialized links removed at collapse time (internal links + the parallel boundary links that were aggregated away). Re-created verbatim on expand. | |
proxyLinks | Array<{ linkId: string; end: 'source' | 'target'; originalPortId: string; originalNodeId?: string; ... | Boundary links that SURVIVED as proxy links: one per (external endpoint) bundle, re-pointed to the placeholder node. Records the original endpoint so expand can restore it, plus how many raw edges it now represents. |
DiagramLoadOptions
tsinterface DiagramLoadOptions
Properties
| Name | Type | Default | Description |
|---|---|---|---|
validate? | 'off' | 'warn' | 'strict' | Structural integrity policy for the incoming document: - 'off' (default) skip validation - 'warn' validate and console.warn a one-line summary with the report - 'strict' validate and throw DiagramValidationError on any error |
FitToContentsOptions
Options for {@link GroupModel.fitToContents}.
tsinterface FitToContentsOptions
Properties
| Name | Type | Default | Description |
|---|---|---|---|
mode? | GroupFitMode | Override the group's stored {@link GroupModel.fitMode} for this call. | |
deepRecursive? | boolean | Deep-recursive fit: fit every descendant group first (deepest first) so a parent fits around already-fitted children. Requires a diagram. |
GroupRect
A resolved rectangle (all four sides present).
tsinterface GroupRect
Properties
| Name | Type | Default | Description |
|---|---|---|---|
x | number | ||
y | number | ||
width | number | ||
height | number |
LaneConfig
Swimlanes & pools as a GENERIC banded group (not BPMN-named). A pool group tiles its child lane groups into bands along one axis; each
lane is an ordinary group (so drop-to-assign, membership, constraints all
reuse the existing machinery). This is intrinsic band config that round-trips.
tsinterface LaneConfig
Properties
| Name | Type | Default | Description |
|---|---|---|---|
role | 'pool' | 'lane' | 'pool' owns the band grid; 'lane' is one band inside a pool. | |
orientation | 'horizontal' | 'vertical' | Band axis. 'horizontal' → lanes are rows stacked along Y (each spans the pool width). 'vertical' → lanes are columns along X (each spans the height). Set on the pool; lanes carry a copy for convenience. | |
laneOrder? | string[] | Pool only: ordered child lane group ids (band order). | |
headerSize? | number | Pool only: title-band thickness reserved along the main axis start (left for horizontal pools, top for vertical pools). | |
weight? | number | Lane only: relative cross-axis size when not fixed (default 1). | |
fixedSize? | number | Lane only: absolute cross-axis size (pins the band, overrides weight). |
MembershipLeaf
tsinterface MembershipLeaf
Properties
| Name | Type | Default | Description |
|---|---|---|---|
field | string | Dot-free key looked up on the node's data map. | |
op | 'eq' | 'ne' | 'in' | 'nin' | 'gt' | 'gte' | 'lt' | 'lte' | 'exists' | 'matches' | ||
value? | unknown | Comparison operand (array for in/nin; regex source string for matches). |
NearestPortHit
What {@link DiagramModel.findNearestPort} found.
tsinterface NearestPortHit
Properties
| Name | Type | Default | Description |
|---|---|---|---|
port | PortModel | ||
node | NodeModel | ||
distance | number | Distance from the query point to the port, in world units. |
NearestPortOptions
Options for {@link DiagramModel.findNearestPort}.
tsinterface NearestPortOptions
Properties
| Name | Type | Default | Description |
|---|---|---|---|
radius? | number | Maximum distance, in world units (default {@link DEFAULT_PORT_SNAP_RADIUS}). | |
filter? | (port: PortModel, node: NodeModel) | Consider only the ports this accepts (e.g. valid targets for the dragged link). | |
portPosition? | (port: PortModel, node: NodeModel) | Where a port actually IS. Defaults to the bounding-box edge midpoint. Callers inside a renderer must pass the SHAPE-AWARE resolver (portWorldPosition) — see the note on findNearestPort. |
SerializedGroup
tsinterface SerializedGroup extends SerializedEntity
Properties
| Name | Type | Default | Description |
|---|---|---|---|
name | string | ||
members | string[] | ||
isCollapsed | boolean | ||
bounds? | { x: number; y: number; width: number; height: number } | ||
layoutType? | LayoutType | ||
layoutConfig? | LayoutConfig | ||
position? | { x: number; y: number } | ||
size? | { width: number; height: number; depth: number } | ||
parentGroupId? | string | ||
padding? | GroupPadding | ||
headerHeight? | number | ||
zIndex? | number | ||
fitMode? | GroupFitMode | ||
constrainChildren? | boolean | ||
collapsedState? | CollapsedState | ||
subgraphLayout? | SubgraphGroupConfig | ||
laneConfig? | LaneConfig | ||
membershipRule? | MembershipRule | ||
capacity? | number |
SerializedLink
tsinterface SerializedLink extends SerializedEntity
Properties
| Name | Type | Default | Description |
|---|---|---|---|
sourcePortId | string | ||
targetPortId | string | ||
sourceNodeId? | string | ||
targetNodeId? | string | ||
pathType | 'direct' | 'orthogonal' | 'smooth' | 'bezier' | ||
router? | LinkRouterName | Explicit routing geometry; absent = derived from pathType. | |
connector? | LinkConnectorName | Explicit polyline rendering; absent = derived from pathType. | |
points | Point[] | ||
segments | PathSegment[] | ||
labels | LinkLabel[] | ||
state | 'default' | 'selected' | 'hovered' | 'highlighted' | ||
style | Partial<LinkStyle> | ||
data | Record<string, any> |
SerializedNode
tsinterface SerializedNode extends SerializedEntity
Properties
| Name | Type | Default | Description |
|---|---|---|---|
position | Point | ||
size | Size | ||
rotation | number | ||
scale | Point | ||
type | string | ||
systemType? | string | ||
definitionId? | string | ||
parentId? | string | ||
children | string[] | ||
ports | SerializedPort[] | ||
state | NodeState | ||
behavior | NodeBehavior | ||
style | Partial<NodeStyle> | ||
data | Record<string, any> | ||
positionMode? | PositioningMode | ||
transformOrigin? | Point | ||
zIndex? | number | Model-level stacking order. OMITTED when the node never set one, so every document written before this field existed round-trips byte-for-byte and no schema migration is needed — absence means "unset", not 0. | |
flexConfig? | FlexItemConfig | ||
gridConfig? | GridItemConfig | ||
portRenderingConfig? | any | ||
dragHandlerConfig? | any | ||
connectionGroup? | string |
SerializedStroke
tsinterface SerializedStroke extends SerializedEntity
Properties
| Name | Type | Default | Description |
|---|---|---|---|
type | 'stroke' | ||
points | StrokePoint[] | ||
style | StrokeStyle | ||
label? | string | An author-supplied name. THE ENTIRE ACCESSIBILITY STORY LIVES ON THIS FIELD — see the a11y note on the renderer's ink layer. Absent for anonymous ink, which is the normal case and is rendered aria-hidden. |
StrokePoint
One sample from the pointer.
pressure is 0..1 and OPTIONAL — a mouse does not have any. It is stored only when
the device actually reported a varying one (see {@link hasPressure}), because a
field that is always 0.5 is noise on the wire and a lie in the model.
It is not decoration: the renderer builds a variable-width outline from it. A pressure that does not change the picture would be exactly the "machinery wired to nothing" this project has shipped in all nine previous waves.
tsinterface StrokePoint
Properties
| Name | Type | Default | Description |
|---|---|---|---|
x | number | ||
y | number | ||
pressure? | number | 0..1. Absent when the device did not report a meaningful one. |
StrokeStyle
How the ink looks. Flat and JSON-safe — this crosses the wire as an op payload.
tsinterface StrokeStyle
Properties
| Name | Type | Default | Description |
|---|---|---|---|
color | string | Any CSS colour. | |
width | number | Nominal width in WORLD units (so ink zooms with the diagram, like everything else). | |
opacity? | number | 0..1. Highlighter ink is translucent; a pen is not. |
SubgraphGroupConfig
A group's own compound-layout configuration — the subset of the GroupInfo layout contract that is intrinsic to the group and round-trips.
tsinterface SubgraphGroupConfig
Properties
| Name | Type | Default | Description |
|---|---|---|---|
algorithm? | 'dagre' | 'elk' | 'grid' | 'inherit' | (string & {}) | Algorithm for THIS group's contents. 'inherit' uses the parent/default. Any name in the layout registry works here (force, spectral, community, or an extension-registered engine), not just the dagre|elk pair Hard-coded — nested layout resolves the name against the registry. An unknown name falls back to the built-in grid rather than throwing. | |
fixed? | boolean | Pinned: neither laid out internally nor moved by the parent layout. | |
layoutOptions? | Record<string, unknown> | Opaque options forwarded to the chosen layout adapter. |
Types
GroupFitMode
How {@link GroupModel.fitToContents} reconciles the freshly computed content rectangle with the group's current rectangle.
exact— snap to the content rectangle (default).grow-only— never shrink below the current rectangle (union).shrink-only— never grow beyond the current rectangle (intersection-ish).
tstype GroupFitMode = 'exact' | 'grow-only' | 'shrink-only';
GroupPadding
Per-side padding (a scalar expands to all four sides).
tstype GroupPadding =
| number
| { top?: number; right?: number; bottom?: number; left?: number };
LinkConnectorName
tstype LinkConnectorName =
| 'straight' // straight segments, hard corners
| 'rounded' // straight segments, cornerRadius arcs (the orthogonal look)
| 'smooth' // catmull-rom-style smoothing through the points
| 'bezier' // cubic bezier between endpoints
| (string & {});
LinkRouterName
. pathType conflated two independent choices:
WHERE the line goes (routing geometry) and HOW the polyline is drawn
(connector rendering). They are now two orthogonal, per-link, serializable
settings, with pathType kept as the back-compat shorthand that derives both
when the explicit fields are absent.
Router names resolve against the engine's RoutingEngine registry, so a custom registered router is addressable per link by its registration name.
tstype LinkRouterName =
| 'straight' // endpoint-to-endpoint, ignores obstacles
| 'orthogonal' // HVH/VHV elbows honouring port sides
| 'manhattan' // grid search with obstacle avoidance + direction-change cost
| 'avoid' // A* obstacle-avoiding router
| 'elk' // delegate geometry to ELK's edge router
| (string & {});
MembershipRule
A SERIALIZABLE declarative membership predicate over a node's
data (never eval'd code). Leaves match one field with an operator; branches
compose with all/any/not. Kept intentionally small and closed so it round-
trips and can be reasoned about / edited as data.
tstype MembershipRule =
| MembershipLeaf
| { all: MembershipRule[] }
| { any: MembershipRule[] }
| { not: MembershipRule };
MemberValidation
Predicate used to gate group membership. Return false to reject a candidate entity from joining the group.
tstype MemberValidation = (candidateId: string, group: GroupModel) => boolean;
Parameters
candidateId: id of the node/group being addedgroup: the group the candidate would join
PositioningMode
Positioning mode
- absolute: Position relative to diagram origin (default, backward compatible)
- relative: Position relative to parent
- layout: Position managed by parent's layout algorithm (future)
tstype PositioningMode = 'absolute' | 'relative' | 'layout';
Was this page helpful?