{
	"$schema": "https://json-schema.org/draft/2020-12/schema",
	"$id": "https://schema.jiscribe.dev/v1/jiscribe.schema.json",
	"title": "CanvasDoc",
	"description": "Root document format for a .jis file used by canvas.\n\nCoordinate system: every position and size (x/y, cx/cy, width/height, rx/ry, points, waypoints) is expressed in CSS pixels (px) within a single shared world-coordinate space. The origin (0,0) is the top-left corner; X increases to the right and Y increases downward (screen convention, NOT math convention). Angles (rotation) are in degrees and turn clockwise. There is no fixed canvas boundary and coordinates may be negative, but for a new document keep the primary content near the origin — roughly x in [0, 1600] and y in [0, 1200] — so it lands inside the initial viewport.",
	"type": "object",
	"required": ["version", "root"],
	"additionalProperties": false,
	"properties": {
		"$schema": {
			"description": "JSON Schema URL for this document.",
			"type": "string"
		},
		"version": {
			"description": "Schema version. Must be 1 for this version of the format.",
			"type": "integer",
			"const": 1
		},
		"background": {
			"description": "Canvas surface color as a literal CSS color string (a concrete color, not a var(...), so the file stays portable). Omit to follow the theme background. When set it is the surface for both display and image export, and the grid line color is derived from it.",
			"type": "string"
		},
		"view": {
			"description": "Display declaration: how much empty space belongs around the drawing, how the view is framed when the document is opened, and whether it may be scrolled past its own edges. Presentation only — objects may sit outside the padding and editing is not constrained by it. Omit it entirely to leave all three to whatever opens the document.",
			"type": "object",
			"additionalProperties": false,
			"properties": {
				"padding": {
					"description": "Empty space in world px kept outside the content on each side. Each side is optional and defaults to 0. This is the margin of rendered and exported images, and the box the initial view is fitted to — declare it here instead of baking the margin into object coordinates.",
					"type": "object",
					"additionalProperties": false,
					"properties": {
						"top": {
							"description": "Space above the content's top edge. Default: 0",
							"type": "number",
							"minimum": 0
						},
						"right": {
							"description": "Space right of the content's right edge. Default: 0",
							"type": "number",
							"minimum": 0
						},
						"bottom": {
							"description": "Space below the content's bottom edge. Default: 0",
							"type": "number",
							"minimum": 0
						},
						"left": {
							"description": "Space left of the content's left edge. Default: 0",
							"type": "number",
							"minimum": 0
						}
					}
				},
				"open": {
					"description": "How to frame the view when the document is opened. Both modes fit the content bounds grown by 'padding'; the axis that is not fitted starts at that axis's start edge. \"fit-width\" fits the width and starts at the top (a document read top to bottom); \"fit-all\" fits the whole drawing and centers it (a diagram taken in at a glance). Omit it to leave the framing alone. It is an intent, not a command: a host that sets its own camera wins, and the zoom is clamped to the canvas's own range.",
					"type": "string",
					"enum": ["fit-width", "fit-all"]
				},
				"scroll": {
					"description": "Whether the document is a bounded page or an endless board. \"content\" walls panning in at the content bounds grown by 'padding' — the same box 'open' frames and an exported image gets, so there is no separate margin to set and a document opened \"fit-width\" cannot be panned sideways off its own page. \"infinite\" is the endless board, and is also what omitting the field means. Like 'open' it is an intent: a host that sets its own scroll limit wins. Only deliberate scrolling is walled in — zooming out still shows the area around the page.",
					"type": "string",
					"enum": ["content", "infinite"]
				}
			}
		},
		"root": {
			"description": "All objects on the canvas (shapes, polylines, groups, connectors) in z-order (back to front). Connectors are mixed in among the objects; array order is the stacking order.",
			"type": "array",
			"items": {
				"$ref": "#/$defs/AnyObjectDoc"
			}
		}
	},
	"$comment": "GENERATED FILE — shape $defs and unions are generated from the shape manifest by `pnpm generate:schema` (packages/doc-schema). Edit shape descriptions in the ObjectDocDefinition entries, and the handwritten parts under packages/doc-schema/generator/templates/.",
	"$defs": {
		"AnyObjectDoc": {
			"description": "Any placeable object at the top level of 'root'. Connectors are allowed here.",
			"oneOf": [
				{
					"$ref": "#/$defs/RectDoc"
				},
				{
					"$ref": "#/$defs/MarkdownDoc"
				},
				{
					"$ref": "#/$defs/EllipseDoc"
				},
				{
					"$ref": "#/$defs/TextDoc"
				},
				{
					"$ref": "#/$defs/DiamondDoc"
				},
				{
					"$ref": "#/$defs/StadiumDoc"
				},
				{
					"$ref": "#/$defs/ParallelogramDoc"
				},
				{
					"$ref": "#/$defs/HexagonDoc"
				},
				{
					"$ref": "#/$defs/CloudDoc"
				},
				{
					"$ref": "#/$defs/DocumentDoc"
				},
				{
					"$ref": "#/$defs/MultiDocumentDoc"
				},
				{
					"$ref": "#/$defs/ActorDoc"
				},
				{
					"$ref": "#/$defs/BrowserWindowDoc"
				},
				{
					"$ref": "#/$defs/TerminalWindowDoc"
				},
				{
					"$ref": "#/$defs/SmartphoneDoc"
				},
				{
					"$ref": "#/$defs/LaptopDoc"
				},
				{
					"$ref": "#/$defs/ServerDoc"
				},
				{
					"$ref": "#/$defs/GearDoc"
				},
				{
					"$ref": "#/$defs/PackageDoc"
				},
				{
					"$ref": "#/$defs/FolderDoc"
				},
				{
					"$ref": "#/$defs/FileDoc"
				},
				{
					"$ref": "#/$defs/EnvelopeDoc"
				},
				{
					"$ref": "#/$defs/QueueDoc"
				},
				{
					"$ref": "#/$defs/LockDoc"
				},
				{
					"$ref": "#/$defs/ShieldDoc"
				},
				{
					"$ref": "#/$defs/LucideIconDoc"
				},
				{
					"$ref": "#/$defs/CalloutDoc"
				},
				{
					"$ref": "#/$defs/NoteDoc"
				},
				{
					"$ref": "#/$defs/BraceDoc"
				},
				{
					"$ref": "#/$defs/BracketWithStemDoc"
				},
				{
					"$ref": "#/$defs/BracketDoc"
				},
				{
					"$ref": "#/$defs/DbDoc"
				},
				{
					"$ref": "#/$defs/StoredDataDoc"
				},
				{
					"$ref": "#/$defs/SubroutineDoc"
				},
				{
					"$ref": "#/$defs/TrapezoidDoc"
				},
				{
					"$ref": "#/$defs/ManualInputDoc"
				},
				{
					"$ref": "#/$defs/CardDoc"
				},
				{
					"$ref": "#/$defs/DelayDoc"
				},
				{
					"$ref": "#/$defs/LoopLimitDoc"
				},
				{
					"$ref": "#/$defs/DisplayDoc"
				},
				{
					"$ref": "#/$defs/ExtractDoc"
				},
				{
					"$ref": "#/$defs/CrossDoc"
				},
				{
					"$ref": "#/$defs/OffPageConnectorDoc"
				},
				{
					"$ref": "#/$defs/RecordDoc"
				},
				{
					"$ref": "#/$defs/UmlPackageDoc"
				},
				{
					"$ref": "#/$defs/UmlComponentDoc"
				},
				{
					"$ref": "#/$defs/PolylineDoc"
				},
				{
					"$ref": "#/$defs/PolygonDoc"
				},
				{
					"$ref": "#/$defs/GroupDoc"
				},
				{
					"$ref": "#/$defs/ContainerDoc"
				},
				{
					"$ref": "#/$defs/StickyDoc"
				},
				{
					"$ref": "#/$defs/SvgDoc"
				},
				{
					"$ref": "#/$defs/ConnectorDoc"
				}
			],
			"$comment": "Branches are tagged by the \"type\" field; each branch pins it with a const, which is what selects the matching branch."
		},
		"GroupChildDoc": {
			"description": "Objects allowed inside a group's children. Connectors are top-level only (root), so they are excluded here.",
			"oneOf": [
				{
					"$ref": "#/$defs/RectDoc"
				},
				{
					"$ref": "#/$defs/MarkdownDoc"
				},
				{
					"$ref": "#/$defs/EllipseDoc"
				},
				{
					"$ref": "#/$defs/TextDoc"
				},
				{
					"$ref": "#/$defs/DiamondDoc"
				},
				{
					"$ref": "#/$defs/StadiumDoc"
				},
				{
					"$ref": "#/$defs/ParallelogramDoc"
				},
				{
					"$ref": "#/$defs/HexagonDoc"
				},
				{
					"$ref": "#/$defs/CloudDoc"
				},
				{
					"$ref": "#/$defs/DocumentDoc"
				},
				{
					"$ref": "#/$defs/MultiDocumentDoc"
				},
				{
					"$ref": "#/$defs/ActorDoc"
				},
				{
					"$ref": "#/$defs/BrowserWindowDoc"
				},
				{
					"$ref": "#/$defs/TerminalWindowDoc"
				},
				{
					"$ref": "#/$defs/SmartphoneDoc"
				},
				{
					"$ref": "#/$defs/LaptopDoc"
				},
				{
					"$ref": "#/$defs/ServerDoc"
				},
				{
					"$ref": "#/$defs/GearDoc"
				},
				{
					"$ref": "#/$defs/PackageDoc"
				},
				{
					"$ref": "#/$defs/FolderDoc"
				},
				{
					"$ref": "#/$defs/FileDoc"
				},
				{
					"$ref": "#/$defs/EnvelopeDoc"
				},
				{
					"$ref": "#/$defs/QueueDoc"
				},
				{
					"$ref": "#/$defs/LockDoc"
				},
				{
					"$ref": "#/$defs/ShieldDoc"
				},
				{
					"$ref": "#/$defs/LucideIconDoc"
				},
				{
					"$ref": "#/$defs/CalloutDoc"
				},
				{
					"$ref": "#/$defs/NoteDoc"
				},
				{
					"$ref": "#/$defs/BraceDoc"
				},
				{
					"$ref": "#/$defs/BracketWithStemDoc"
				},
				{
					"$ref": "#/$defs/BracketDoc"
				},
				{
					"$ref": "#/$defs/DbDoc"
				},
				{
					"$ref": "#/$defs/StoredDataDoc"
				},
				{
					"$ref": "#/$defs/SubroutineDoc"
				},
				{
					"$ref": "#/$defs/TrapezoidDoc"
				},
				{
					"$ref": "#/$defs/ManualInputDoc"
				},
				{
					"$ref": "#/$defs/CardDoc"
				},
				{
					"$ref": "#/$defs/DelayDoc"
				},
				{
					"$ref": "#/$defs/LoopLimitDoc"
				},
				{
					"$ref": "#/$defs/DisplayDoc"
				},
				{
					"$ref": "#/$defs/ExtractDoc"
				},
				{
					"$ref": "#/$defs/CrossDoc"
				},
				{
					"$ref": "#/$defs/OffPageConnectorDoc"
				},
				{
					"$ref": "#/$defs/RecordDoc"
				},
				{
					"$ref": "#/$defs/UmlPackageDoc"
				},
				{
					"$ref": "#/$defs/UmlComponentDoc"
				},
				{
					"$ref": "#/$defs/PolylineDoc"
				},
				{
					"$ref": "#/$defs/PolygonDoc"
				},
				{
					"$ref": "#/$defs/GroupDoc"
				},
				{
					"$ref": "#/$defs/ContainerDoc"
				},
				{
					"$ref": "#/$defs/StickyDoc"
				},
				{
					"$ref": "#/$defs/SvgDoc"
				}
			],
			"$comment": "Branches are tagged by the \"type\" field; each branch pins it with a const, which is what selects the matching branch."
		},
		"RectDoc": {
			"description": "Rectangle shape.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"rect\".",
					"type": "string",
					"const": "rect"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels. Default when created from the palette: 100",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Optional: omit it and the height follows the text — the box is sized to the smallest one the wrapped text fits in, and re-sized whenever the text or the width changes. Default when created from the palette: 100",
					"type": "number",
					"minimum": 0
				},
				"rx": {
					"description": "Corner radius (SVG rx). Default: 0",
					"type": "number",
					"minimum": 0,
					"default": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"fill": {
					"$ref": "#/$defs/FillStyle/properties/fill"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"$ref": "#/$defs/TextStyle/properties/textAlign"
				},
				"verticalAlign": {
					"$ref": "#/$defs/TextStyle/properties/verticalAlign"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"$ref": "#/$defs/TextStyle/properties/fontSize"
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"MarkdownDoc": {
			"description": "A card whose text is Markdown source, rendered as HTML on the canvas. Use it for notes, specs, summaries, and any block of prose that needs headings, lists, tables, code fences, or math ($...$ inline, $$...$$ block) — a rect CANNOT do this, its text is always plain. Same rect-based geometry (x/y/width/height) as RectDoc. Write the body as ordinary Markdown in `text`, using \"\\n\" for line breaks. Defaults suit a document: 300x200, left/top aligned, and a theme-following fill so the card reads as a page. Image export flattens the rendering to plain text, so do not rely on it for exported diagrams.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width", "height"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"markdown\".",
					"type": "string",
					"const": "markdown"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"x": {
					"description": "Left-edge X coordinate.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate.",
					"type": "number"
				},
				"width": {
					"description": "Width in pixels. Default when created from the palette: 300",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Height in pixels. Content taller than this is clipped, so give a long body enough room. Default when created from the palette: 200",
					"type": "number",
					"minimum": 0
				},
				"rx": {
					"description": "Corner radius (SVG rx). Default: 0",
					"type": "number",
					"minimum": 0,
					"default": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"fill": {
					"description": "Fill color as a CSS color string, or \"auto\" to follow the theme surface. Default: \"auto\" (unlike other shapes, which default to transparent)",
					"type": "string",
					"default": "auto"
				},
				"text": {
					"description": "Markdown source to render. Default: \"\"",
					"type": "string",
					"default": ""
				},
				"textAlign": {
					"description": "Horizontal alignment of the rendered blocks. Default: \"left\"",
					"allOf": [
						{
							"$ref": "#/$defs/TextAlign"
						}
					],
					"default": "left"
				},
				"verticalAlign": {
					"description": "Vertical placement of the rendered body. Default: \"top\"",
					"allOf": [
						{
							"$ref": "#/$defs/VerticalAlign"
						}
					],
					"default": "top"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"description": "Base font size in pixels; headings and code scale relative to it. Default: 16",
					"type": "number",
					"minimum": 1,
					"default": 16
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"EllipseDoc": {
			"description": "Ellipse (oval) shape.",
			"type": "object",
			"required": ["id", "type", "cx", "cy", "rx", "ry"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"ellipse\".",
					"type": "string",
					"const": "ellipse"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"cx": {
					"description": "Center X coordinate.",
					"type": "number"
				},
				"cy": {
					"description": "Center Y coordinate.",
					"type": "number"
				},
				"rx": {
					"description": "Horizontal radius in pixels. Default when created from the palette: 50",
					"type": "number",
					"minimum": 0
				},
				"ry": {
					"description": "Vertical radius in pixels. Default when created from the palette: 50",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"fill": {
					"$ref": "#/$defs/FillStyle/properties/fill"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"$ref": "#/$defs/TextStyle/properties/textAlign"
				},
				"verticalAlign": {
					"$ref": "#/$defs/TextStyle/properties/verticalAlign"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"$ref": "#/$defs/TextStyle/properties/fontSize"
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"TextDoc": {
			"description": "Standalone text with no box drawn around it. `x` / `y` are the top-left of the text; its width and height are measured from the content, so they are not stored and growing text extends to the right and down. Under `rotation` or a flip, \"right and down\" means the shape's own axes, `x` / `y` staying put. Set `textLayout: \"block\"` with a `width` for body copy instead: the text then wraps inside that width, and only the height stays measured.",
			"type": "object",
			"required": ["id", "type", "x", "y"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"text\".",
					"type": "string",
					"const": "text"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"textLayout": {
					"description": "How the text is laid out. \"label\" (the default when omitted) makes the box the text's own extent: lines break where the text has a newline and nowhere else, so a long line widens the object instead of wrapping. \"block\" is body copy: the box takes the stored `width`, the text wraps inside it, and the height stays measured from the wrapped lines. Use \"block\" for paragraphs, \"label\" for captions and annotations.",
					"type": "string",
					"enum": ["label", "block"]
				},
				"width": {
					"description": "Box width in pixels, padding included, that the text wraps in. Required with `textLayout: \"block\"` and allowed only there — the label layout measures its own width, and a width on it is invalid. There is no `height` field in either layout: the height always follows from the text.",
					"type": "number",
					"minimum": 0
				},
				"x": {
					"description": "Left-edge X coordinate. In the label layout there is no width field: the box is measured from the content and grows to the right (along the shape's own axis when rotated or flipped, so this coordinate never moves). In the block layout the box is `width` wide from this edge.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate. There is no height field: the box is measured from the content and grows downward (along the shape's own axis when rotated or flipped, so this coordinate never moves).",
					"type": "number"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"description": "Horizontal text alignment. Default: \"left\" (overrides the shared default \"center\").",
					"allOf": [
						{
							"$ref": "#/$defs/TextAlign"
						}
					],
					"default": "left"
				},
				"verticalAlign": {
					"description": "Vertical text alignment. Default: \"top\" (overrides the shared default \"middle\").",
					"allOf": [
						{
							"$ref": "#/$defs/VerticalAlign"
						}
					],
					"default": "top"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"$ref": "#/$defs/TextStyle/properties/fontSize"
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"DiamondDoc": {
			"description": "Diamond (rhombus) shape, typically used for decision/branch nodes in flowcharts. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering is a diamond. Text is laid out within the full bounding box (not clipped to the diamond interior).",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"diamond\".",
					"type": "string",
					"const": "diamond"
				}
			}
		},
		"StadiumDoc": {
			"description": "Stadium (pill) shape with fully rounded ends, typically used for start/end terminators in flowcharts. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering is a stadium. Text is laid out within the full bounding box.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"stadium\".",
					"type": "string",
					"const": "stadium"
				}
			}
		},
		"ParallelogramDoc": {
			"description": "Parallelogram shape (top edge shifted right), typically used for input/output steps in flowcharts. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering is a parallelogram. Text is laid out with a small horizontal inset to stay inside the slanted sides.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"parallelogram\".",
					"type": "string",
					"const": "parallelogram"
				}
			}
		},
		"HexagonDoc": {
			"description": "Hexagon shape with pointed left/right caps, typically used for preparation steps in flowcharts or emphasis nodes. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering is a hexagon. Text is laid out with a small horizontal inset to stay inside the caps.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"hexagon\".",
					"type": "string",
					"const": "hexagon"
				}
			}
		},
		"CloudDoc": {
			"description": "Cloud shape, typically used for external systems/networks in architecture diagrams or fuzzy concepts in brainstorming. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering is a cloud. Text is laid out in a reduced central region inside the bumps, so give it generous width/height for longer text.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"cloud\".",
					"type": "string",
					"const": "cloud"
				}
			}
		},
		"DocumentDoc": {
			"description": "Document shape (rect with a wavy bottom edge), typically used for reports/files in flowcharts or deliverables in business diagrams. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering is a document. Text is laid out above the bottom wave band.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"document\".",
					"type": "string",
					"const": "document"
				}
			}
		},
		"MultiDocumentDoc": {
			"description": "Multi-document shape (three stacked document sheets), used for report batches / file sets in flowcharts. The front sheet sits at the bottom-left and the two back sheets step toward the top-right. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is confined to the front sheet, above its bottom wave band.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"multiDocument\".",
					"type": "string",
					"const": "multiDocument"
				}
			}
		},
		"ActorDoc": {
			"description": "Actor (stick figure) shape, typically used for users/roles in use-case diagrams or stakeholders in business diagrams. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. The stick figure fills the whole box. Text is drawn as a label below the box, auto-sized to the text itself, so the box may be kept small without making the text unreadable. A portrait aspect ratio (e.g. 80x100) looks best.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/BoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"actor\".",
					"type": "string",
					"const": "actor"
				}
			}
		},
		"BrowserWindowDoc": {
			"description": "Browser window shape (a frame with a title bar carrying three window buttons): the symbol that stands for a web UI, e.g. to show which screen calls which service. Its title bar and buttons are fractions of the box, so it reads at around its default size and turns into a giant bar with giant buttons when blown up — it is a node to point at, not a frame to lay a screen out inside. For a screen mockup, draw the regions with rect (or container for a titled one). Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is laid out in the content area below the title bar, so a landscape aspect ratio (e.g. 160x110) suits it.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"browserWindow\".",
					"type": "string",
					"const": "browserWindow"
				}
			}
		},
		"TerminalWindowDoc": {
			"description": "Terminal window shape (the same frame as browserWindow, with a shell prompt in the title bar instead of the window buttons), typically used for CLIs, shell sessions and scripts. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is laid out in the content area below the title bar, so a landscape aspect ratio (e.g. 160x110) suits it.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"terminalWindow\".",
					"type": "string",
					"const": "terminalWindow"
				}
			}
		},
		"SmartphoneDoc": {
			"description": "Smartphone shape, typically used for mobile clients. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is laid out on the screen, which is narrow — keep it to a word or two, or widen the box. A portrait aspect ratio (e.g. 70x120) looks best.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"smartphone\".",
					"type": "string",
					"const": "smartphone"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels. Default when created from the palette: 70",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Optional: omit it and the height follows the text — the box is sized to the smallest one the wrapped text fits in, and re-sized whenever the text or the width changes. Default when created from the palette: 120",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"fill": {
					"$ref": "#/$defs/FillStyle/properties/fill"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"$ref": "#/$defs/TextStyle/properties/textAlign"
				},
				"verticalAlign": {
					"$ref": "#/$defs/TextStyle/properties/verticalAlign"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"description": "Font size in pixels. Default: 14 (overrides the shared default 16).",
					"type": "number",
					"minimum": 1,
					"default": 14
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"LaptopDoc": {
			"description": "Laptop shape (screen over a splayed base), typically used for desktop and web clients. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is laid out on the screen, so the base band at the bottom of the box stays clear. A landscape aspect ratio (e.g. 140x100) looks best.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"laptop\".",
					"type": "string",
					"const": "laptop"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels. Default when created from the palette: 140",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Optional: omit it and the height follows the text — the box is sized to the smallest one the wrapped text fits in, and re-sized whenever the text or the width changes. Default when created from the palette: 100",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"fill": {
					"$ref": "#/$defs/FillStyle/properties/fill"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"$ref": "#/$defs/TextStyle/properties/textAlign"
				},
				"verticalAlign": {
					"$ref": "#/$defs/TextStyle/properties/verticalAlign"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"description": "Font size in pixels. Default: 14 (overrides the shared default 16).",
					"type": "number",
					"minimum": 1,
					"default": 14
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"ServerDoc": {
			"description": "Server rack shape (a box divided into stacked units, each with a status light), typically used for hosts, nodes and long-running processes in architecture diagrams. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is drawn as a label below the box, auto-sized to the text itself, so the box may be kept small without making the text unreadable. A portrait aspect ratio (e.g. 90x110) looks best. Prefer \"package\" for something that is deployed rather than something that runs.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/BoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"server\".",
					"type": "string",
					"const": "server"
				}
			}
		},
		"GearDoc": {
			"description": "Gear shape, typically used for services, batch jobs and daemons — work that runs on its own rather than being called through a UI. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is drawn as a label below the box, auto-sized to the text itself, so the box may be kept small without making the text unreadable. A square aspect ratio (e.g. 100x100) looks best; a stretched box gives a stretched gear.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/BoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"gear\".",
					"type": "string",
					"const": "gear"
				}
			}
		},
		"PackageDoc": {
			"description": "Isometric box shape, typically used for libraries, build artifacts and deployment units. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is drawn as a label below the box, auto-sized to the text itself, so the box may be kept small without making the text unreadable. The hexagon is a cube in isometric projection, so it reads as a cube only when the box is slightly taller than wide (e.g. 95x110); a square box widens it. Prefer \"server\" for something that runs rather than something that is deployed.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/BoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"package\".",
					"type": "string",
					"const": "package"
				}
			}
		},
		"FolderDoc": {
			"description": "Folder shape (a tab on the top-left corner), typically used for directories and for grouping. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is laid out below the tab. For a frame that other objects are placed inside, use a container shape instead — this one is a plain icon and does not hold children.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"folder\".",
					"type": "string",
					"const": "folder"
				}
			}
		},
		"FileDoc": {
			"description": "File shape (a folded top-right corner), typically used for source files and configuration. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is laid out below the fold, so a portrait aspect ratio (e.g. 100x120) looks best. Distinct from the flowchart \"document\" (wavy bottom edge, a flowchart step) and \"card\" (clipped top-left corner), and from \"note\", which folds the same corner but is a comment box about the diagram rather than a thing the diagram is about.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"file\".",
					"type": "string",
					"const": "file"
				}
			}
		},
		"EnvelopeDoc": {
			"description": "Closed envelope shape, typically used for a single message or event. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is drawn as a label below the box, auto-sized to the text itself, so the box may be kept small without making the text unreadable. A landscape aspect ratio (e.g. 120x84) looks best. Prefer \"queue\" for the buffer messages sit in rather than for one message.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/BoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"envelope\".",
					"type": "string",
					"const": "envelope"
				}
			}
		},
		"QueueDoc": {
			"description": "Queue shape (a row of cells), typically used for job queues, message queues and topics. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is drawn as a label below the box, auto-sized to the text itself, so the box may be kept small without making the text unreadable. It carries no direction mark, so which end is the head is whatever the connectors say. A wide, short aspect ratio (e.g. 160x70) looks best.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/BoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"queue\".",
					"type": "string",
					"const": "queue"
				}
			}
		},
		"LockDoc": {
			"description": "Padlock shape, typically used for authentication steps and protected resources. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is drawn as a label below the box, auto-sized to the text itself, so the box may be kept small without making the text unreadable. A portrait aspect ratio (e.g. 80x100) looks best. Prefer \"shield\" for a boundary that other things sit behind.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/BoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"lock\".",
					"type": "string",
					"const": "lock"
				}
			}
		},
		"ShieldDoc": {
			"description": "Shield shape, typically used for security boundaries and trust zones. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is laid out in the straight-sided upper part only, since the lower part tapers to a point — keep it short, or give the shape more height. Prefer \"lock\" for a single protected resource.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"shield\".",
					"type": "string",
					"const": "shield"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels. Default when created from the palette: 100",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Optional: omit it and the height follows the text — the box is sized to the smallest one the wrapped text fits in, and re-sized whenever the text or the width changes. Default when created from the palette: 120",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"fill": {
					"$ref": "#/$defs/FillStyle/properties/fill"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"$ref": "#/$defs/TextStyle/properties/textAlign"
				},
				"verticalAlign": {
					"$ref": "#/$defs/TextStyle/properties/verticalAlign"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"description": "Font size in pixels. Default: 14 (overrides the shared default 16).",
					"type": "number",
					"minimum": 1,
					"default": 14
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"LucideIconDoc": {
			"description": "A named pictogram from the bundled Lucide icon set, drawn as line art. Decoration, not a node: it holds no text and cannot be a connector endpoint, so place it beside the shape it marks (a rect, a container header, a sticky) and connect arrows to that shape instead. For a picture that is itself a node, use a labelled pictogram such as \"server\", \"package\" or \"db\". The drawing is scaled uniformly to the smaller side of the box and centred, so keep the box square (the 64x64 default) unless margin is wanted. `stroke` is the icon's own color and `strokeWidth` its line weight, both honoured at any size.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width", "height"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"lucideIcon\".",
					"type": "string",
					"const": "lucideIcon"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"icon": {
					"description": "Which icon to draw, as a kebab-case name from the bundled Lucide set (1767 icons). Any name in that set is accepted, not only the ones listed below. A superseded name (\"user-circle\") or another spelling (\"fileText\", \"file_text\") resolves to the current one, and a name that resolves to nothing is rejected with the nearest candidates named, so a wrong guess costs one correction rather than a broken document. Do not invent a name from another icon set (\"account_circle\", \"document-text\") — those resolve to nothing. Commonly wanted names — people: user, users, user-round, circle-user, contact; devices: monitor, smartphone, tablet, laptop, server, hard-drive, cpu, printer, webcam; infrastructure: cloud, cloud-upload, cloud-download, database, network, router, wifi, globe, radio-tower; files: file, file-text, files, folder, folder-open, archive, save, book, clipboard; messaging: mail, message-square, message-circle, send, bell, phone, rss, share-2, link, at-sign; security: lock, lock-open, shield, shield-check, key, key-round, fingerprint-pattern, eye, eye-off, scan-face; status: check, circle-check, x, circle-x, triangle-alert, info, circle-question-mark, octagon-alert, ban, loader, hourglass, clock, timer; actions: plus, minus, pencil, square-pen, trash-2, copy, clipboard-copy, download, upload, refresh-cw, rotate-ccw, play, pause, settings, sliders-horizontal, funnel, search, zoom-in, external-link; flow: arrow-right, arrow-left, arrow-up, arrow-down, arrow-right-left, chevron-right, chevron-down, corner-down-right, git-branch, git-merge, workflow, split, merge; data and code: chart-line, chart-bar, chart-pie, table, list, layers, box, package, boxes, binary, braces, code, terminal, bug; business: building, building-2, factory, store, shopping-cart, credit-card, banknote, receipt, briefcase, calendar, users-round; other: star, heart, flag, bookmark, tag, map-pin, lightbulb, zap, flame, sparkles, wrench, hammer, cog, gauge, activity, target, trending-up, trending-down, thumbs-up, face-slightly-smiling, alarm-clock, rocket, gift, coffee, leaf, sun, moon. Omitted = \"star\".",
					"type": "string",
					"default": "star"
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels. Default when created from the palette: 64",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Default when created from the palette: 64",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"description": "Lock aspect ratio during resize. Default: true (overrides the shared default false).",
					"type": "boolean",
					"default": true
				}
			}
		},
		"CalloutDoc": {
			"description": "Speech-bubble callout, typically used for annotations and explanatory comments. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering is a bubble. The tail stays inside the bounding box, occupying a quarter of it on its side; text is laid out in the bubble body beside it. Point the tail at the annotated object via `tail` (default: bottom edge, position 0.2).",
			"type": "object",
			"required": ["id", "type", "x", "y", "width"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"callout\".",
					"type": "string",
					"const": "callout"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"tail": {
					"description": "Tail placement: the tip sits on the bounding box's `side` edge at `position`. Choose the side facing the annotated object. The tail base stays in a fixed slot on that edge (left/top half vs right/bottom half, following the tip's half), so the tail always leans like a classic speech bubble. Omitted = bottom at 0.2.",
					"type": "object",
					"required": ["side", "position"],
					"additionalProperties": false,
					"properties": {
						"side": {
							"description": "Which edge of the bounding box the tail tip sits on.",
							"type": "string",
							"enum": ["top", "right", "bottom", "left"]
						},
						"position": {
							"description": "Position of the tip along that edge (0 = left/top end, 1 = right/bottom end).",
							"type": "number",
							"minimum": 0,
							"maximum": 1
						}
					}
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels. Default when created from the palette: 160",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Optional: omit it and the height follows the text — the box is sized to the smallest one the wrapped text fits in, and re-sized whenever the text or the width changes. Default when created from the palette: 110",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"fill": {
					"$ref": "#/$defs/FillStyle/properties/fill"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"$ref": "#/$defs/TextStyle/properties/textAlign"
				},
				"verticalAlign": {
					"$ref": "#/$defs/TextStyle/properties/verticalAlign"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"$ref": "#/$defs/TextStyle/properties/fontSize"
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"NoteDoc": {
			"description": "Note shape: a box with its top-right corner folded back, holding a comment about the diagram — the UML note. It uses the same rect geometry (x/y/width/height) as RectDoc and only swaps the drawing, so it takes text inside the box, unlike the group markers in this package. Give it a landscape box (e.g. 180x110) and left-aligned text, and attach it to what it comments on with a connector. Two shapes are easily mistaken for it, and neither is the same thing: \"document\" (a wavy bottom edge) is a flowchart step that produces paperwork, and \"file\" is a portrait pictogram standing for a file on disk. Reach for \"note\" when the box holds prose *about* the diagram, and for those two when the shape *is* one of the things the diagram is about. Where the comment should point at one spot on one shape, CalloutDoc (a bubble with a tail) says so more directly.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"note\".",
					"type": "string",
					"const": "note"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels. Default when created from the palette: 180",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Optional: omit it and the height follows the text — the box is sized to the smallest one the wrapped text fits in, and re-sized whenever the text or the width changes. Default when created from the palette: 110",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"fill": {
					"$ref": "#/$defs/FillStyle/properties/fill"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"description": "Horizontal text alignment. Default: \"left\" (overrides the shared default \"center\").",
					"allOf": [
						{
							"$ref": "#/$defs/TextAlign"
						}
					],
					"default": "left"
				},
				"verticalAlign": {
					"description": "Vertical text alignment. Default: \"top\" (overrides the shared default \"middle\").",
					"allOf": [
						{
							"$ref": "#/$defs/VerticalAlign"
						}
					],
					"default": "top"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"$ref": "#/$defs/TextStyle/properties/fontSize"
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"BraceDoc": {
			"description": "Curly brace shape, used to mark a run of shapes as one group and name it. Uses the same rect-based geometry (x/y/width/height) as RectDoc, but the box is the bracket alone: its short side is how far the curve bulges, its long side how far the arms reach. \"direction\" is the way the tip points, away from what is being grouped — a \"left\" brace is the typographic \"{\" and groups what is to its right, so place the box just left of that run and give it a small width (e.g. 24x160). \"tipPosition\" (0..1) moves the tip along the span, from the top for a left/right brace and from the left for an up/down one. Text is drawn as a label just beyond the tip, auto-sized to the text itself and outside the box, so the box stays a thin band however long the label is. The brace has no fill. Beyond the four edge midpoints it offers a connect point at its tip, \"tip\": aim a connector at the brace with { \"kind\": \"connectPoint\", \"id\": \"tip\" } so the line meets the cusp instead of a midpoint of the thin band.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width", "height"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"brace\".",
					"type": "string",
					"const": "brace"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"direction": {
					"description": "Which way the tip points, away from the shapes being grouped: the arms reach the opposite edge, where those shapes are. \"left\" is the typographic \"{\" and groups what is to its right; \"down\" sits under a row and groups what is above it. Must match the box's proportions — use \"left\"/\"right\" for a tall box and \"up\"/\"down\" for a wide one. Omitted = \"left\".",
					"type": "string",
					"enum": ["left", "right", "up", "down"]
				},
				"tipPosition": {
					"description": "Where the tip sits along the span (the box's long side): 0 = top end for a left/right brace and left end for an up/down one, 1 = the other end. The label hangs off the tip, so this is also what moves the label. Omitted = 0.5.",
					"type": "number",
					"minimum": 0,
					"maximum": 1
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels. Default when created from the palette: 24",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Default when created from the palette: 160",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"$ref": "#/$defs/TextStyle/properties/textAlign"
				},
				"verticalAlign": {
					"$ref": "#/$defs/TextStyle/properties/verticalAlign"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"$ref": "#/$defs/TextStyle/properties/fontSize"
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"BracketWithStemDoc": {
			"description": "Square bracket with a stem, used to mark a run of shapes as one group and name it at a chosen point. Same box and same \"direction\" as BracketDoc, except that the spine sits half way into the box and a straight stem runs out of it, at right angles, to the outer edge. \"tipPosition\" (0..1) moves the stem along the span, from the top for a left/right bracket and from the left for an up/down one, and the label hangs off the stem's end, auto-sized to the text itself and outside the box. Use BracketDoc instead when the label needs to point at nothing in particular. It has no fill. Beyond the four edge midpoints it offers a connect point named \"tip\", the stem's end, so a connector can meet the stem where the label does.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width", "height"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"bracketWithStem\".",
					"type": "string",
					"const": "bracketWithStem"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"direction": {
					"description": "Which way the stem points, away from the shapes being grouped: the feet reach the opposite edge, where those shapes are. \"left\" is the typographic \"[\" and groups what is to its right; \"down\" sits under a row and groups what is above it. Must match the box's proportions — use \"left\"/\"right\" for a tall box and \"up\"/\"down\" for a wide one. Omitted = \"left\".",
					"type": "string",
					"enum": ["left", "right", "up", "down"]
				},
				"tipPosition": {
					"description": "Where the stem leaves the spine, along the span (the box's long side): 0 = top end for a left/right bracket and left end for an up/down one, 1 = the other end. The label hangs off the stem's end, so this is also what moves the label. Omitted = 0.5.",
					"type": "number",
					"minimum": 0,
					"maximum": 1
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels. Default when created from the palette: 24",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Default when created from the palette: 160",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"$ref": "#/$defs/TextStyle/properties/textAlign"
				},
				"verticalAlign": {
					"$ref": "#/$defs/TextStyle/properties/verticalAlign"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"$ref": "#/$defs/TextStyle/properties/fontSize"
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"BracketDoc": {
			"description": "Square bracket shape, used to mark a run of shapes as one group and name it. Same box and same \"direction\" as BraceDoc — a \"left\" bracket is the typographic \"[\" and groups what is to its right — but it is drawn with straight lines only: a spine along the outer edge with a foot at each end, reaching towards the grouped shapes. It has no \"tipPosition\", because nothing on it singles out a place along the spine; the label always sits just beyond the middle of the spine, auto-sized to the text itself and outside the box. Use BracketWithStemDoc instead when the label should point at one particular place in the run. The bracket has no fill. Beyond the four edge midpoints it offers a connect point named \"tip\", which for a plain bracket is the middle of the spine — the same place its label points from.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width", "height"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"bracket\".",
					"type": "string",
					"const": "bracket"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"direction": {
					"description": "Which side the spine sits on, away from the shapes being grouped: the feet reach the opposite edge, where those shapes are. \"left\" is the typographic \"[\" and groups what is to its right; \"down\" sits under a row and groups what is above it. Must match the box's proportions — use \"left\"/\"right\" for a tall box and \"up\"/\"down\" for a wide one. Omitted = \"left\".",
					"type": "string",
					"enum": ["left", "right", "up", "down"]
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels. Default when created from the palette: 24",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Default when created from the palette: 160",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"$ref": "#/$defs/TextStyle/properties/textAlign"
				},
				"verticalAlign": {
					"$ref": "#/$defs/TextStyle/properties/verticalAlign"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"$ref": "#/$defs/TextStyle/properties/fontSize"
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"DbDoc": {
			"description": "Database cylinder shape, typically used for data stores in architecture or ER diagrams. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering is a cylinder. Text is laid out in the body region below the top cap ellipse (not the full bounding box).",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"db\".",
					"type": "string",
					"const": "db"
				}
			}
		},
		"StoredDataDoc": {
			"description": "Stored-data shape (a rectangle whose left/right edges are arcs both bowing left, like a drum segment) — the generic storage symbol for files / caches that are not specifically a database (use DbDoc for databases). Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is laid out between the two side arcs.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"storedData\".",
					"type": "string",
					"const": "storedData"
				}
			}
		},
		"SubroutineDoc": {
			"description": "Predefined-process (subroutine) box: a rectangle with a vertical bar near each side, for calls to a defined sub-procedure. Uses the same rect-based geometry (x/y/width/height) as RectDoc; text is inset horizontally to stay between the bars.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"subroutine\".",
					"type": "string",
					"const": "subroutine"
				}
			}
		},
		"TrapezoidDoc": {
			"description": "Trapezoid (wide top, narrow bottom), typically used for manual-operation steps in flowcharts. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering is a trapezoid.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"trapezoid\".",
					"type": "string",
					"const": "trapezoid"
				}
			}
		},
		"ManualInputDoc": {
			"description": "Manual-input shape whose top edge slopes up toward the right, used for keyed/manual entry steps. Uses the same rect-based geometry (x/y/width/height) as RectDoc; text sits below the sloping top edge.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"manualInput\".",
					"type": "string",
					"const": "manualInput"
				}
			}
		},
		"CardDoc": {
			"description": "Card: a rectangle with the top-left corner cut off, used for punched-card style data in flowcharts. Uses the same rect-based geometry (x/y/width/height) as RectDoc.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"card\".",
					"type": "string",
					"const": "card"
				}
			}
		},
		"DelayDoc": {
			"description": "Delay shape: a rectangle whose right edge is a semicircular bulge, used for wait/delay steps in flowcharts. Uses the same rect-based geometry (x/y/width/height) as RectDoc.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"delay\".",
					"type": "string",
					"const": "delay"
				}
			}
		},
		"LoopLimitDoc": {
			"description": "Loop-limit shape (a rectangle with both top corners cut off), marking the start of a loop in flowcharts; set \"flipY\": true to mark the loop end. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text sits below the top bevels.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"loopLimit\".",
					"type": "string",
					"const": "loopLimit"
				}
			}
		},
		"DisplayDoc": {
			"description": "Display shape with a pointed left edge and a rounded right cap, used for output-to-display steps in flowcharts. Uses the same rect-based geometry (x/y/width/height) as RectDoc.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"display\".",
					"type": "string",
					"const": "display"
				}
			}
		},
		"ExtractDoc": {
			"description": "The flowchart \"extract\" symbol — an upward triangle (apex at the top), used for extract/merge/marker nodes. Uses the same rect-based geometry (x/y/width/height) as RectDoc. The triangle fills the whole box and the text is drawn as a label below it, auto-sized to the text itself — so the box does not need to be widened for a long name, and leaving the text out keeps a bare marker.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/BoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"extract\".",
					"type": "string",
					"const": "extract"
				}
			}
		},
		"CrossDoc": {
			"description": "Cross (plus) marker, used to mark junctions and for emphasis. Uses the same rect-based geometry (x/y/width/height) as RectDoc. The arms fill the whole box and the text is drawn as a label below it, auto-sized to the text itself — so the box does not need to be widened for a long note, and leaving the text out keeps a bare marker.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/BoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"cross\".",
					"type": "string",
					"const": "cross"
				}
			}
		},
		"OffPageConnectorDoc": {
			"description": "Off-page connector: a home-plate pentagon (rectangle tapering to a downward point) marking a jump to another page/section of a flowchart, usually paired with an on-page connector by a short label. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering is a pentagon. Text sits in the rectangular band above the point.",
			"type": "object",
			"allOf": [
				{
					"$ref": "#/$defs/AutoHeightBoxShapeDoc"
				}
			],
			"properties": {
				"type": {
					"description": "Must be \"offPageConnector\".",
					"type": "string",
					"const": "offPageConnector"
				}
			}
		},
		"RecordDoc": {
			"description": "Record: a titled box with compartments of rows underneath (a UML class, an ER entity, an ontology concept with its properties). Uses the same rect-based geometry (x/y/width/height) as RectDoc. Unlike every other shape, its \"text\" is a keyed object of slots — an optional \"stereotype\" band, \"name\" for the title band, then \"attributes\" and \"operations\" for the compartments — and the plain-string form is rejected. Which slots you write is what gives the box its compartments: omit \"operations\" for a two-compartment box, omit both for a plain titled box. Typography belongs to each slot, so there are no shape-wide textAlign/fontSize/... fields here. The box is not auto-fitted to its rows.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width", "height"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"record\".",
					"type": "string",
					"const": "record"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels.",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Not auto-fitted: the compartments divide up whatever height you give. Every compartment above the bottom one takes the height its own rows need (21 per row, at least one row, plus 4); the bottom one takes the remainder and clips whatever falls past the box. Size it yourself: a title band over one compartment of N rows fits exactly at 32 + 21 * N, and a second compartment of M rows adds 21 * M + 4 (25 when it is empty). A written \"stereotype\" adds a band of its own above the title, 28 more at the default fontSize. Either header band grows with its content — a larger fontSize, a newline, or text too long for the width makes it taller (1.5 * fontSize per displayed line + 7) and pushes the compartments down, so add that much here too.",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"fill": {
					"description": "Fill color as a CSS color string, or \"auto\" to follow the theme surface. Default: \"auto\" (unlike most shapes, which default to transparent)",
					"type": "string",
					"default": "auto"
				},
				"text": {
					"description": "The text slots. Not a string: a record keeps its title and its compartments apart, and each slot carries its own typography instead of the shape-wide fields other shapes have. Which slots you write is what gives the box its compartments — write \"attributes\" alone for a two-compartment box (an ER entity, a DTO), add \"operations\" for a UML class, omit both for a plain titled box; \"stereotype\" is a band rather than a compartment and is what marks an interface, an abstract class, or an enum. Default: { \"name\": { \"text\": \"\" }, \"attributes\": { \"text\": [] } }",
					"type": "object",
					"additionalProperties": false,
					"properties": {
						"stereotype": {
							"description": "Stereotype band above the title, holding a UML stereotype such as \"<<interface>>\", \"<<abstract>>\", or \"<<enum>>\". Optional, and unlike a compartment it has no empty form: omit the slot and the band is not drawn at all. No divider is drawn between it and the title, so the two read as one header.",
							"type": "object",
							"additionalProperties": false,
							"required": ["text"],
							"properties": {
								"text": {
									"description": "Stereotype string, conventionally written between guillemets (\"<<interface>>\"). Write a plain string unless part of the text has to be drawn differently; the array of runs is only for that (a bold word, a phrase in red), and the runs are concatenated in order to form the text. Default: \"\"",
									"anyOf": [
										{
											"type": "string"
										},
										{
											"type": "array",
											"items": {
												"$ref": "#/$defs/TextRun"
											},
											"minItems": 1
										}
									],
									"default": ""
								},
								"textAlign": {
									"description": "Horizontal text alignment. Default: \"center\"",
									"allOf": [
										{
											"$ref": "#/$defs/TextAlign"
										}
									],
									"default": "center"
								},
								"verticalAlign": {
									"description": "Vertical text alignment. Default: \"middle\"",
									"allOf": [
										{
											"$ref": "#/$defs/VerticalAlign"
										}
									],
									"default": "middle"
								},
								"fontColor": {
									"$ref": "#/$defs/TextStyle/properties/fontColor"
								},
								"fontSize": {
									"description": "Font size in pixels. Default: 14 (the 21px row pitch and the height formula 32 + 21 * rows.length are sized for it)",
									"type": "number",
									"minimum": 1,
									"default": 14
								},
								"fontFamily": {
									"$ref": "#/$defs/TextStyle/properties/fontFamily"
								},
								"fontWeight": {
									"$ref": "#/$defs/TextStyle/properties/fontWeight"
								},
								"fontStyle": {
									"$ref": "#/$defs/TextStyle/properties/fontStyle"
								},
								"textDecoration": {
									"$ref": "#/$defs/TextStyle/properties/textDecoration"
								}
							}
						},
						"name": {
							"description": "Title slot, shown in the top band. Always drawn, whether or not you write it.",
							"type": "object",
							"additionalProperties": false,
							"required": ["text"],
							"properties": {
								"text": {
									"description": "Title string. Write a plain string unless part of the text has to be drawn differently; the array of runs is only for that (a bold word, a phrase in red), and the runs are concatenated in order to form the text. Default: \"\"",
									"anyOf": [
										{
											"type": "string"
										},
										{
											"type": "array",
											"items": {
												"$ref": "#/$defs/TextRun"
											},
											"minItems": 1
										}
									],
									"default": ""
								},
								"textAlign": {
									"description": "Horizontal text alignment. Default: \"center\"",
									"allOf": [
										{
											"$ref": "#/$defs/TextAlign"
										}
									],
									"default": "center"
								},
								"verticalAlign": {
									"description": "Vertical text alignment. Default: \"middle\"",
									"allOf": [
										{
											"$ref": "#/$defs/VerticalAlign"
										}
									],
									"default": "middle"
								},
								"fontColor": {
									"$ref": "#/$defs/TextStyle/properties/fontColor"
								},
								"fontSize": {
									"description": "Font size in pixels. Default: 14 (the 21px row pitch and the height formula 32 + 21 * rows.length are sized for it)",
									"type": "number",
									"minimum": 1,
									"default": 14
								},
								"fontFamily": {
									"$ref": "#/$defs/TextStyle/properties/fontFamily"
								},
								"fontWeight": {
									"description": "Font weight (e.g. \"normal\", \"bold\", \"700\"). Default: \"bold\" (a record's title is bold unless you override it)",
									"type": "string",
									"default": "bold"
								},
								"fontStyle": {
									"$ref": "#/$defs/TextStyle/properties/fontStyle"
								},
								"textDecoration": {
									"$ref": "#/$defs/TextStyle/properties/textDecoration"
								}
							}
						},
						"attributes": {
							"description": "Attribute compartment (fields, properties, ER columns), drawn under the title band. Omit the whole slot to leave the compartment off the box; an empty array keeps the compartment and draws it empty.",
							"type": "object",
							"additionalProperties": false,
							"required": ["text"],
							"properties": {
								"text": {
									"description": "Attribute rows, one array entry per line (no newlines inside an entry). Write a plain string unless part of the row has to be drawn differently; the array of runs is only for that (a bold word, a phrase in red), and the runs are concatenated in order to form the row. Default: []",
									"type": "array",
									"items": {
										"anyOf": [
											{
												"type": "string"
											},
											{
												"type": "array",
												"items": {
													"$ref": "#/$defs/TextRun"
												},
												"minItems": 1
											}
										]
									},
									"default": []
								},
								"textAlign": {
									"description": "Horizontal text alignment. Default: \"left\" (a record slot's default, not the shared \"center\")",
									"allOf": [
										{
											"$ref": "#/$defs/TextAlign"
										}
									],
									"default": "left"
								},
								"verticalAlign": {
									"description": "Vertical text alignment. Default: \"top\" (a record slot's default, not the shared \"middle\")",
									"allOf": [
										{
											"$ref": "#/$defs/VerticalAlign"
										}
									],
									"default": "top"
								},
								"fontColor": {
									"$ref": "#/$defs/TextStyle/properties/fontColor"
								},
								"fontSize": {
									"description": "Font size in pixels. Default: 14 (the 21px row pitch and the height formula 32 + 21 * rows.length are sized for it)",
									"type": "number",
									"minimum": 1,
									"default": 14
								},
								"fontFamily": {
									"$ref": "#/$defs/TextStyle/properties/fontFamily"
								},
								"fontWeight": {
									"$ref": "#/$defs/TextStyle/properties/fontWeight"
								},
								"fontStyle": {
									"$ref": "#/$defs/TextStyle/properties/fontStyle"
								},
								"textDecoration": {
									"$ref": "#/$defs/TextStyle/properties/textDecoration"
								}
							}
						},
						"operations": {
							"description": "Operation compartment (methods, behaviors), drawn under the attributes. Omit the whole slot for a shape that has no operations — a UML class with only attributes is drawn with two compartments, not three.",
							"type": "object",
							"additionalProperties": false,
							"required": ["text"],
							"properties": {
								"text": {
									"description": "Operation rows, one array entry per line (no newlines inside an entry). Write a plain string unless part of the row has to be drawn differently; the array of runs is only for that (a bold word, a phrase in red), and the runs are concatenated in order to form the row. Default: []",
									"type": "array",
									"items": {
										"anyOf": [
											{
												"type": "string"
											},
											{
												"type": "array",
												"items": {
													"$ref": "#/$defs/TextRun"
												},
												"minItems": 1
											}
										]
									},
									"default": []
								},
								"textAlign": {
									"description": "Horizontal text alignment. Default: \"left\" (a record slot's default, not the shared \"center\")",
									"allOf": [
										{
											"$ref": "#/$defs/TextAlign"
										}
									],
									"default": "left"
								},
								"verticalAlign": {
									"description": "Vertical text alignment. Default: \"top\" (a record slot's default, not the shared \"middle\")",
									"allOf": [
										{
											"$ref": "#/$defs/VerticalAlign"
										}
									],
									"default": "top"
								},
								"fontColor": {
									"$ref": "#/$defs/TextStyle/properties/fontColor"
								},
								"fontSize": {
									"description": "Font size in pixels. Default: 14 (the 21px row pitch and the height formula 32 + 21 * rows.length are sized for it)",
									"type": "number",
									"minimum": 1,
									"default": 14
								},
								"fontFamily": {
									"$ref": "#/$defs/TextStyle/properties/fontFamily"
								},
								"fontWeight": {
									"$ref": "#/$defs/TextStyle/properties/fontWeight"
								},
								"fontStyle": {
									"$ref": "#/$defs/TextStyle/properties/fontStyle"
								},
								"textDecoration": {
									"$ref": "#/$defs/TextStyle/properties/textDecoration"
								}
							}
						}
					}
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"UmlPackageDoc": {
			"description": "UML package shape (a rectangle with a tab on its top-left corner), typically used for namespaces, modules and layers in UML package diagrams. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. The rect is the outer bounds of the whole silhouette, tab included, and the text is laid out in the body below the tab. Distinct from \"package\", which is an isometric box for a build artifact or deployment unit, and from \"container\", which actually holds the objects placed inside it — this one is a plain shape with no children.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"umlPackage\".",
					"type": "string",
					"const": "umlPackage"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels. Default when created from the palette: 160",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Optional: omit it and the height follows the text — the box is sized to the smallest one the wrapped text fits in, and re-sized whenever the text or the width changes. Default when created from the palette: 108",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"fill": {
					"description": "Fill color as a CSS color string, or \"auto\" to follow the theme surface/panel background (resolved at render time). Default: \"auto\" (overrides the shared default \"transparent\").",
					"type": "string",
					"default": "auto"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"$ref": "#/$defs/TextStyle/properties/textAlign"
				},
				"verticalAlign": {
					"$ref": "#/$defs/TextStyle/properties/verticalAlign"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"description": "Font size in pixels. Default: 14 (overrides the shared default 16).",
					"type": "number",
					"minimum": 1,
					"default": 14
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"description": "Font weight (e.g. \"normal\", \"bold\", \"700\"). Default: \"bold\" (overrides the shared default \"normal\").",
					"type": "string",
					"default": "bold"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"UmlComponentDoc": {
			"description": "UML 2 component shape (a rectangle carrying the component symbol in its top-right corner), typically used for replaceable parts of a system in UML component diagrams. Uses the same rect-based geometry (x/y/width/height) as RectDoc; only the rendering differs. Text is laid out over the whole box, so keep the name short enough to clear the symbol, or widen the box. Prefer \"record\" with a <<component>> stereotype when the part needs compartments of its own.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"umlComponent\".",
					"type": "string",
					"const": "umlComponent"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels. Default when created from the palette: 160",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Optional: omit it and the height follows the text — the box is sized to the smallest one the wrapped text fits in, and re-sized whenever the text or the width changes. Default when created from the palette: 90",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"fill": {
					"description": "Fill color as a CSS color string, or \"auto\" to follow the theme surface/panel background (resolved at render time). Default: \"auto\" (overrides the shared default \"transparent\").",
					"type": "string",
					"default": "auto"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"$ref": "#/$defs/TextStyle/properties/textAlign"
				},
				"verticalAlign": {
					"$ref": "#/$defs/TextStyle/properties/verticalAlign"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"description": "Font size in pixels. Default: 14 (overrides the shared default 16).",
					"type": "number",
					"minimum": 1,
					"default": 14
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"description": "Font weight (e.g. \"normal\", \"bold\", \"700\"). Default: \"bold\" (overrides the shared default \"normal\").",
					"type": "string",
					"default": "bold"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"PolylineDoc": {
			"description": "Open polyline (non-closed path).",
			"type": "object",
			"required": ["id", "type", "points"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"polyline\".",
					"type": "string",
					"const": "polyline"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"points": {
					"description": "Ordered list of vertices.",
					"type": "array",
					"items": {
						"$ref": "#/$defs/Point"
					},
					"minItems": 2
				},
				"startArrow": {
					"description": "Arrow at the start point.",
					"$ref": "#/$defs/ArrowType"
				},
				"endArrow": {
					"description": "Arrow at the end point.",
					"$ref": "#/$defs/ArrowType"
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				}
			}
		},
		"PolygonDoc": {
			"description": "Closed polygon shape.",
			"type": "object",
			"required": ["id", "type", "points"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"polygon\".",
					"type": "string",
					"const": "polygon"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"points": {
					"description": "Ordered list of vertices (automatically closed).",
					"type": "array",
					"items": {
						"$ref": "#/$defs/Point"
					},
					"minItems": 3
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"fill": {
					"$ref": "#/$defs/FillStyle/properties/fill"
				}
			}
		},
		"GroupDoc": {
			"description": "A group containing child objects.",
			"type": "object",
			"required": ["id", "type", "children"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"group\".",
					"type": "string",
					"const": "group"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"children": {
					"description": "Child objects inside this group. Connectors are top-level only and not allowed here. A group must contain at least one child.",
					"type": "array",
					"minItems": 1,
					"items": {
						"$ref": "#/$defs/GroupChildDoc"
					}
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"ContainerDoc": {
			"description": "Container (\"frame\") shape: a titled rectangle that marks off a region of the diagram, typically a module, subsystem or bounded context. Uses the same rect-based geometry (x/y/width/height) as RectDoc. `text` is the title and is drawn in the top header band, never in the body; the body is click-through, so objects lying over it stay directly selectable. Objects are put inside it by geometry alone: give them coordinates within the box and place them after the container in `root` so they paint on top. A container has no `children` and does not carry its contents when it moves — wrap them in a GroupDoc when they must move together. The palette entries Frame / Boundary / Zone are all this type: Boundary is a container with `strokeDashType: \"dashed\"`, Zone one with a tinted `fill`.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width", "height"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"container\".",
					"type": "string",
					"const": "container"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"headerFill": {
					"description": "Header band fill as a CSS color string, or \"auto\" to follow the theme surface color. Independent of `fill`, which paints the (click-through) body. Default: \"auto\"",
					"type": "string",
					"default": "auto"
				},
				"headerHeight": {
					"description": "Height of the title header band in pixels, measured down from the top edge. Capped at `height` when drawn. Omitted = 28.",
					"type": "number",
					"minimum": 1
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels. Default when created from the palette: 240",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Default when created from the palette: 160",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"fill": {
					"$ref": "#/$defs/FillStyle/properties/fill"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"description": "Horizontal text alignment. Default: \"left\" (overrides the shared default \"center\").",
					"allOf": [
						{
							"$ref": "#/$defs/TextAlign"
						}
					],
					"default": "left"
				},
				"verticalAlign": {
					"$ref": "#/$defs/TextStyle/properties/verticalAlign"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"description": "Font size in pixels. Default: 14 (overrides the shared default 16).",
					"type": "number",
					"minimum": 1,
					"default": 14
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"description": "Font weight (e.g. \"normal\", \"bold\", \"700\"). Default: \"bold\" (overrides the shared default \"normal\").",
					"type": "string",
					"default": "bold"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"StickyDoc": {
			"description": "Sticky note annotation.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"sticky\".",
					"type": "string",
					"const": "sticky"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels. Default when created from the palette: 160",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Optional: omit it and the height follows the text — the box is sized to the smallest one the wrapped text fits in, and re-sized whenever the text or the width changes. Default when created from the palette: 120",
					"type": "number",
					"minimum": 0
				},
				"fill": {
					"description": "Fill color as a CSS color string, or \"auto\" to follow the theme surface/panel background (resolved at render time). Default: \"#fef9c3\" (overrides the shared default \"transparent\").",
					"type": "string",
					"default": "#fef9c3"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"$ref": "#/$defs/TextStyle/properties/textAlign"
				},
				"verticalAlign": {
					"$ref": "#/$defs/TextStyle/properties/verticalAlign"
				},
				"fontColor": {
					"description": "Font color as a CSS color string, or \"auto\" to follow the theme foreground. Sticky notes override the usual \"auto\" default with \"#000000\" (black), because a sticky is drawn on a light paper-colored background. Default: \"#000000\"",
					"type": "string",
					"default": "#000000"
				},
				"fontSize": {
					"description": "Font size in pixels. Default: 14 (overrides the shared default 16).",
					"type": "number",
					"minimum": 1,
					"default": 14
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"SvgDoc": {
			"description": "Raw inline SVG embedded as an opaque box. Use this only for visuals that the built-in shapes cannot express (icons, logos, ready-made technical figures). The SVG content is scaled to fit the box (its intrinsic size is taken from the markup's viewBox automatically). The SVG is sanitized at render time (scripts, event handlers, and external references are stripped). It is NOT a connector target and has no text/stroke/fill styling of its own.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width", "height", "svgText"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"svg\".",
					"type": "string",
					"const": "svg"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"x": {
					"description": "Left-edge X coordinate.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate.",
					"type": "number"
				},
				"width": {
					"description": "Display width in pixels (the box the SVG is fitted into).",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Display height in pixels (the box the SVG is fitted into).",
					"type": "number",
					"minimum": 0
				},
				"svgText": {
					"description": "Inline SVG markup, starting with a <svg ...> root element. Include a viewBox so the content scales to fit the box (if absent, the markup's width/height, or 100x100, is used). Must be self-contained: no <script>, no event handlers (on*), and no external references (href/xlink:href to URLs). These are removed when rendered.",
					"type": "string"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"ConnectorDoc": {
			"description": "Connector (arrow) linking two endpoints.",
			"type": "object",
			"required": ["id", "type", "source", "target"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"description": "Must be \"connector\".",
					"type": "string",
					"const": "connector"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"points": {
					"description": "Ordered list of the route's vertices from source to target, in world coordinates - the corners the line bends at. Endpoint coordinates are NOT included; they are defined by source/target and resolved dynamically. Empty (the normal case) lets the engine route the whole path. Non-empty, these points ARE the path: under the default \"orthogonal\" shape consecutive points must share x or y, and the first/last must share the axis its endpoint is left on, because nothing straightens or re-routes them. Use vertices only when a specific route matters.",
					"type": "array",
					"items": {
						"$ref": "#/$defs/Point"
					},
					"default": []
				},
				"routing": {
					"description": "Shape of the connector's segments. \"orthogonal\" keeps every segment axis-aligned, so the line bends only at right angles. \"straight\" lets segments run at any angle: a single direct line, or a polyline through the \"points\" vertices. Optional; omitting it means \"orthogonal\" (the default). This chooses the shape only - whether the path is engine-routed or authored is decided by \"points\".",
					"type": "string",
					"enum": ["straight", "orthogonal"]
				},
				"source": {
					"description": "Where the connector starts.",
					"$ref": "#/$defs/EndpointRef"
				},
				"target": {
					"description": "Where the connector ends.",
					"$ref": "#/$defs/EndpointRef"
				},
				"startArrow": {
					"description": "Arrow at the start point.",
					"$ref": "#/$defs/ArrowType"
				},
				"endArrow": {
					"description": "Arrow at the end point.",
					"$ref": "#/$defs/ArrowType"
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"label": {
					"description": "Optional text annotation drawn on the connector (an edge label such as \"Yes\"/\"No\"). A connector has NO top-level text; put the label here. Omit it for no label. Typography is a SUBSET of the shape text vocabulary: only fontColor, fontFamily, fontSize, and fontWeight apply. A label is always plain text — for Markdown use a separate object of type \"markdown\". It has NO textAlign or verticalAlign — do not add those keys here.",
					"type": "object",
					"required": ["text"],
					"additionalProperties": false,
					"properties": {
						"text": {
							"description": "Label text. Plain text only (no markdown). Multiple lines are allowed with \"\\n\".",
							"type": "string"
						},
						"position": {
							"description": "Where the label sits along the path, as a fraction of the path length from source (0) to target (1). Optional; defaults to 0.5 (midpoint).",
							"type": "number",
							"minimum": 0,
							"maximum": 1
						},
						"offset": {
							"description": "Signed perpendicular offset from the path in world units (left of the source→target direction is positive). Optional; defaults to 0.",
							"type": "number"
						},
						"fontColor": {
							"$ref": "#/$defs/TextStyle/properties/fontColor"
						},
						"fontFamily": {
							"$ref": "#/$defs/TextStyle/properties/fontFamily"
						},
						"fontSize": {
							"$ref": "#/$defs/TextStyle/properties/fontSize"
						},
						"fontWeight": {
							"$ref": "#/$defs/TextStyle/properties/fontWeight"
						},
						"fill": {
							"description": "Label background color (CSS color, or \"auto\"). Omitted/\"auto\" uses the canvas background to mask the line behind the label (knockout). Use \"transparent\" to let the line show through.",
							"$ref": "#/$defs/FillStyle/properties/fill"
						},
						"stroke": {
							"description": "Label border color (CSS color, or \"auto\"). Only visible when strokeWidth > 0.",
							"$ref": "#/$defs/StrokeStyle/properties/stroke"
						},
						"strokeWidth": {
							"description": "Label border width in pixels. Default 0 (no border).",
							"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
						},
						"strokeDashType": {
							"description": "Label border line style: \"solid\" (default), \"dashed\", or \"dotted\". Only visible when strokeWidth > 0.",
							"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
						}
					}
				}
			},
			"$comment": "A connector must have at least one owned endpoint. Both endpoints being free (no owner) is invalid — that is an ink/polyline, not a connector.",
			"not": {
				"required": ["source", "target"],
				"properties": {
					"source": {
						"not": {
							"required": ["owner"]
						}
					},
					"target": {
						"not": {
							"required": ["owner"]
						}
					}
				}
			}
		},
		"EndpointRef": {
			"description": "Connector endpoint — either attached to an object or floating.",
			"oneOf": [
				{
					"$ref": "#/$defs/OwnedEndpointRef"
				},
				{
					"$ref": "#/$defs/FreeEndpointRef"
				}
			]
		},
		"OwnedEndpointRef": {
			"description": "Endpoint attached to a specific object.",
			"type": "object",
			"required": ["owner", "anchor"],
			"additionalProperties": false,
			"properties": {
				"owner": {
					"$ref": "#/$defs/OwnerRef"
				},
				"anchor": {
					"oneOf": [
						{
							"$ref": "#/$defs/CenterAnchorSpec"
						},
						{
							"$ref": "#/$defs/ConnectPointAnchorSpec"
						},
						{
							"$ref": "#/$defs/EdgeAnchorSpec"
						}
					]
				}
			}
		},
		"FreeEndpointRef": {
			"description": "Endpoint floating at a fixed point in canvas space.",
			"type": "object",
			"required": ["anchor"],
			"additionalProperties": false,
			"properties": {
				"anchor": {
					"$ref": "#/$defs/FreeAnchorSpec"
				}
			}
		},
		"OwnerRef": {
			"description": "Reference to an object on the canvas by ID. The referenced object must be connectable: rect / markdown / ellipse / text / diamond / stadium / parallelogram / hexagon / cloud / document / multiDocument / actor / browserWindow / terminalWindow / smartphone / laptop / server / gear / package / folder / file / envelope / queue / lock / shield / callout / note / brace / bracketWithStem / bracket / db / storedData / subroutine / trapezoid / manualInput / card / delay / loopLimit / display / extract / cross / offPageConnector / record / umlPackage / umlComponent / container / sticky (NOT lucideIcon / polyline / polygon / group / svg / connector).",
			"type": "object",
			"required": ["id"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "ID of the target object.",
					"type": "string"
				}
			}
		},
		"CenterAnchorSpec": {
			"description": "Anchor at the geometric center of an object.",
			"type": "object",
			"required": ["kind"],
			"additionalProperties": false,
			"properties": {
				"kind": {
					"type": "string",
					"const": "center"
				}
			}
		},
		"ConnectPointAnchorSpec": {
			"description": "Anchor at a named connection point on an object.",
			"type": "object",
			"required": ["kind", "id"],
			"additionalProperties": false,
			"properties": {
				"kind": {
					"type": "string",
					"const": "connectPoint"
				},
				"id": {
					"$ref": "#/$defs/ConnectPointId"
				}
			}
		},
		"EdgeAnchorSpec": {
			"description": "Anchor at an arbitrary position along one edge of an object. Reach for a named anchor first: CenterAnchorSpec when the connector should simply point at the object, ConnectPointAnchorSpec for an edge midpoint or a point the shape type names itself. Use this only when the connection has to land somewhere those cannot express — several parallel lines arriving at one edge, or a line meeting a specific row of a record. \"side\" and \"t\" describe the object's own local space, before rotation and flips, so the anchor stays on the same part of the shape however the shape is turned.",
			"type": "object",
			"required": ["kind", "side", "t"],
			"additionalProperties": false,
			"properties": {
				"kind": {
					"type": "string",
					"const": "edge"
				},
				"side": {
					"description": "Which of the object's four local edges the anchor rides.",
					"type": "string",
					"enum": ["top", "right", "bottom", "left"]
				},
				"t": {
					"description": "Position along that edge, from 0 to 1. Measured left to right on \"top\" / \"bottom\" and top to bottom on \"left\" / \"right\". 0.5 is the edge midpoint — the same place as the matching ConnectPointId, which is the clearer way to write it.",
					"type": "number",
					"minimum": 0,
					"maximum": 1
				}
			}
		},
		"FreeAnchorSpec": {
			"description": "Anchor at an arbitrary point in canvas space.",
			"type": "object",
			"required": ["kind", "point"],
			"additionalProperties": false,
			"properties": {
				"kind": {
					"type": "string",
					"const": "free"
				},
				"point": {
					"$ref": "#/$defs/Point"
				}
			}
		},
		"ConnectPointId": {
			"description": "Named connection point on a shape. Every connectable shape has the four edge midpoints; a shape type may name further points of its own, and the group markers (brace / bracket / bracketWithStem) add \"tip\" for the cusp, spine middle, or stem end the label points from. An id the target shape's type does not name falls back to that shape's center, so \"tip\" on any other type is a silent miss rather than an error. The geometric center is not a connect point; use CenterAnchorSpec (\"kind\": \"center\") for the center.",
			"type": "string",
			"enum": ["topCenter", "rightCenter", "bottomCenter", "leftCenter", "tip"]
		},
		"Point": {
			"description": "A 2D coordinate.",
			"type": "object",
			"required": ["x", "y"],
			"additionalProperties": false,
			"properties": {
				"x": {
					"type": "number"
				},
				"y": {
					"type": "number"
				}
			}
		},
		"MetaDoc": {
			"description": "Optional metadata attached to any object.",
			"type": "object",
			"properties": {
				"name": {
					"description": "Display name of the object.",
					"type": "string"
				},
				"description": {
					"description": "Arbitrary description.",
					"type": "string"
				},
				"reference": {
					"description": "Relative path to another file this object refers to. Opened by the host application; jiscribe itself does not resolve it.",
					"type": "string"
				}
			},
			"additionalProperties": true
		},
		"StrokeStyle": {
			"description": "Stroke (outline) style properties.",
			"type": "object",
			"properties": {
				"stroke": {
					"description": "Stroke color as a CSS color string, or \"auto\" to follow the theme foreground (resolved at render time). Default: \"auto\"",
					"type": "string",
					"default": "auto"
				},
				"strokeWidth": {
					"description": "Stroke width in pixels. Default: 2",
					"type": "number",
					"minimum": 0,
					"default": 2
				},
				"strokeDashType": {
					"description": "Dash pattern. Default: \"solid\"",
					"allOf": [
						{
							"$ref": "#/$defs/StrokeDashType"
						}
					],
					"default": "solid"
				}
			}
		},
		"FillStyle": {
			"description": "Fill (background) style properties.",
			"type": "object",
			"properties": {
				"fill": {
					"description": "Fill color as a CSS color string, or \"auto\" to follow the theme surface/panel background (resolved at render time). Default: \"transparent\"",
					"type": "string",
					"default": "transparent"
				}
			}
		},
		"TextStyle": {
			"description": "Text content and typography properties.",
			"type": "object",
			"properties": {
				"text": {
					"description": "Text content to display. Write a plain string unless part of the text has to be drawn differently; the array of runs is only for that (a bold word, a phrase in red), and the runs are concatenated in order to form the text. Default: \"\"",
					"anyOf": [
						{
							"type": "string"
						},
						{
							"type": "array",
							"items": {
								"$ref": "#/$defs/TextRun"
							},
							"minItems": 1
						}
					],
					"default": ""
				},
				"textAlign": {
					"description": "Horizontal text alignment. Default: \"center\"",
					"allOf": [
						{
							"$ref": "#/$defs/TextAlign"
						}
					],
					"default": "center"
				},
				"verticalAlign": {
					"description": "Vertical text alignment. Default: \"middle\"",
					"allOf": [
						{
							"$ref": "#/$defs/VerticalAlign"
						}
					],
					"default": "middle"
				},
				"fontColor": {
					"description": "Font color as a CSS color string, or \"auto\" to follow the theme foreground (resolved at render time). Default: \"auto\". NOTE: sticky notes override this default to \"#000000\" — see StickyDoc.fontColor.",
					"type": "string",
					"default": "auto"
				},
				"fontSize": {
					"description": "Font size in pixels. Default: 16",
					"type": "number",
					"minimum": 1,
					"default": 16
				},
				"fontFamily": {
					"description": "Font family. Pick one of the four the canvas ships faces for: \"\\\"Source Sans 3\\\", \\\"Noto Sans JP\\\", sans-serif\" (sans, the default), \"\\\"Source Serif 4\\\", \\\"Noto Serif JP\\\", serif\" (serif), \"\\\"Source Code Pro\\\", \\\"Noto Sans JP\\\", monospace\" (monospace), \"Caveat, \\\"Klee One\\\", cursive\" (handwriting). Any other value still loads, but is drawn only if the viewer happens to have that font, and the shape's box is measured against whatever it falls back to. Default: \"\\\"Source Sans 3\\\", \\\"Noto Sans JP\\\", sans-serif\"",
					"type": "string",
					"default": "\"Source Sans 3\", \"Noto Sans JP\", sans-serif"
				},
				"fontWeight": {
					"description": "Font weight (e.g. \"normal\", \"bold\", \"700\"). Default: \"normal\"",
					"type": "string",
					"default": "normal"
				},
				"fontStyle": {
					"description": "Font style: \"normal\" or \"italic\". Default: \"normal\"",
					"type": "string",
					"default": "normal"
				},
				"textDecoration": {
					"description": "Text decoration lines: \"underline\", \"line-through\", or \"underline line-through\" for both. \"none\" or omitted means no decoration. Default: \"none\"",
					"type": "string",
					"default": "none"
				},
				"textVerticalBasis": {
					"description": "Which box `verticalAlign` measures against. \"region\" (the default) uses the area the shape keeps clear of its own decoration — a cylinder's caps, a document's wavy foot — which differs per shape, so shapes of different types drawn at one height put their text on different centres. \"frame\" uses the whole height instead, so a row of mixed types drawn at one height reads as one line of text; the text may then run over the shape's own decoration, which `diagnose` warns about. Horizontal placement is unaffected either way. Default: \"region\"",
					"allOf": [
						{
							"$ref": "#/$defs/TextVerticalBasis"
						}
					],
					"default": "region"
				}
			}
		},
		"TextRun": {
			"description": "One stretch of a text and the typography it alone is drawn with. Every field left out is drawn with the shape's (or the slot's) own typography, so a run carries the difference and not the whole style. There is no alignment here: it places the whole text, not part of it.",
			"type": "object",
			"required": ["text"],
			"additionalProperties": false,
			"properties": {
				"text": {
					"description": "The characters of this stretch of the text.",
					"type": "string"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"$ref": "#/$defs/TextStyle/properties/fontSize"
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				}
			}
		},
		"TransformStyle": {
			"description": "Transformation properties (rotation, flip).",
			"type": "object",
			"properties": {
				"rotation": {
					"description": "Rotation angle in degrees (clockwise). Default: 0",
					"type": "number",
					"default": 0
				},
				"flipX": {
					"description": "Horizontal flip. Default: false",
					"type": "boolean",
					"default": false
				},
				"flipY": {
					"description": "Vertical flip. Default: false",
					"type": "boolean",
					"default": false
				},
				"lockAspectRatio": {
					"description": "Lock aspect ratio during resize. Default: false",
					"type": "boolean",
					"default": false
				}
			}
		},
		"BoxShapeDoc": {
			"description": "Shared structure of the plain box shapes that always state a height: rect geometry plus the Stroke / Fill / Text / Transform styles. Each concrete shape def pins `type` with a const.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width", "height"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"type": "string"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels.",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels.",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"fill": {
					"$ref": "#/$defs/FillStyle/properties/fill"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"$ref": "#/$defs/TextStyle/properties/textAlign"
				},
				"verticalAlign": {
					"$ref": "#/$defs/TextStyle/properties/verticalAlign"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"$ref": "#/$defs/TextStyle/properties/fontSize"
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"AutoHeightBoxShapeDoc": {
			"description": "Shared structure of the plain box shapes that size themselves from their text when no height is given: rect geometry plus the Stroke / Fill / Text / Transform styles. Each concrete shape def pins `type` with a const.",
			"type": "object",
			"required": ["id", "type", "x", "y", "width"],
			"additionalProperties": false,
			"properties": {
				"id": {
					"description": "Unique identifier.",
					"type": "string"
				},
				"type": {
					"type": "string"
				},
				"meta": {
					"$ref": "#/$defs/MetaDoc"
				},
				"x": {
					"description": "Left-edge X coordinate of the bounding box.",
					"type": "number"
				},
				"y": {
					"description": "Top-edge Y coordinate of the bounding box.",
					"type": "number"
				},
				"width": {
					"description": "Bounding-box width in pixels.",
					"type": "number",
					"minimum": 0
				},
				"height": {
					"description": "Bounding-box height in pixels. Optional: omit it and the height follows the text — the box is sized to the smallest one the wrapped text fits in, and re-sized whenever the text or the width changes.",
					"type": "number",
					"minimum": 0
				},
				"stroke": {
					"$ref": "#/$defs/StrokeStyle/properties/stroke"
				},
				"strokeWidth": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeWidth"
				},
				"strokeDashType": {
					"$ref": "#/$defs/StrokeStyle/properties/strokeDashType"
				},
				"fill": {
					"$ref": "#/$defs/FillStyle/properties/fill"
				},
				"text": {
					"$ref": "#/$defs/TextStyle/properties/text"
				},
				"textAlign": {
					"$ref": "#/$defs/TextStyle/properties/textAlign"
				},
				"verticalAlign": {
					"$ref": "#/$defs/TextStyle/properties/verticalAlign"
				},
				"fontColor": {
					"$ref": "#/$defs/TextStyle/properties/fontColor"
				},
				"fontSize": {
					"$ref": "#/$defs/TextStyle/properties/fontSize"
				},
				"fontFamily": {
					"$ref": "#/$defs/TextStyle/properties/fontFamily"
				},
				"fontWeight": {
					"$ref": "#/$defs/TextStyle/properties/fontWeight"
				},
				"fontStyle": {
					"$ref": "#/$defs/TextStyle/properties/fontStyle"
				},
				"textDecoration": {
					"$ref": "#/$defs/TextStyle/properties/textDecoration"
				},
				"textVerticalBasis": {
					"$ref": "#/$defs/TextStyle/properties/textVerticalBasis"
				},
				"rotation": {
					"$ref": "#/$defs/TransformStyle/properties/rotation"
				},
				"flipX": {
					"$ref": "#/$defs/TransformStyle/properties/flipX"
				},
				"flipY": {
					"$ref": "#/$defs/TransformStyle/properties/flipY"
				},
				"lockAspectRatio": {
					"$ref": "#/$defs/TransformStyle/properties/lockAspectRatio"
				}
			}
		},
		"StrokeDashType": {
			"description": "Dash pattern for stroke/border.",
			"type": "string",
			"enum": ["solid", "dashed", "dotted"]
		},
		"TextAlign": {
			"description": "Horizontal text alignment.",
			"type": "string",
			"enum": ["left", "center", "right"]
		},
		"VerticalAlign": {
			"description": "Vertical text alignment.",
			"type": "string",
			"enum": ["top", "middle", "bottom"]
		},
		"TextVerticalBasis": {
			"description": "Box a body text's vertical alignment is measured against.",
			"type": "string",
			"enum": ["region", "frame"]
		},
		"ArrowType": {
			"description": "Arrow shape at a connector endpoint. Includes UML relationship markers and ER crow's foot cardinality marks.",
			"type": "string",
			"enum": [
				"FilledTriangle",
				"ConcaveTriangle",
				"OpenArrow",
				"HollowTriangle",
				"FilledDiamond",
				"HollowDiamond",
				"Circle",
				"HollowCircle",
				"Cross",
				"CrowFootMany",
				"CrowFootOneMany",
				"CrowFootZeroMany",
				"CrowFootOne",
				"CrowFootZeroOne",
				"None"
			]
		}
	}
}
