{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://openeik.org/schemas/0.1/proposed/drawings/svg-profile.json",
  "$comment": "Proposed for OpenEik 0.2: Part XIV, drawings, section 6. Written by hand from the outline of Part XIV, not generated: tools/generate-schemas.mjs keeps this folder and lists none of it in index.json. No file of OpenEik 0.1 is held to it; a validator applies it only when asked for the proposal (@openeik/tools: proposals [\"drawings\"]). @openeik/tools reads it in src/drawings-svg.js, from the bundled copy in src/schemas.js.",
  "title": "OpenEik drawing SVG 0.1",
  "description": "The profile of an issued drawing's SVG (Part XIV, section 6, proposed for 0.2) as data: the elements and attributes it allows, what it forbids, the forms of its values and references, and its limits. A validator and a host's parser share it. It is a schema that asserts nothing: its member x-eik-svg-profile holds the profile. Safety comes from this allowlist and a validator, not from sanitising: anything it does not allow is refused. The rules that read it are XIV.6.12, rules 1 to 27.",
  "x-eik-svg-profile": {
    "profile": "openeik-drawing-svg/0.1",
    "namespace": "http://www.w3.org/2000/svg",
    "root": "svg",
    "paperUnit": "mm",
    "limits": {
      "bytes": 67108864,
      "elements": 2000000,
      "depth": 32,
      "expanded": 1000000
    },
    "numbers": {
      "pattern": "^-?(?:0|[1-9][0-9]*)(?:\\.[0-9]*[1-9])?$",
      "negativeZero": false,
      "decimals": 3,
      "viewportMatrixDecimals": 9,
      "note": "Fixed decimals: no exponent, no +, no leading zeros, no trailing zeros after the point, -0 written 0, an integer part always (0.5, never .5). At most three decimals, but for the numbers of a viewport group's transform (the derivation's matrix), at most nine. No unit but the root's mm. Lists of numbers are separated by white space, a comma, or both."
    },
    "elements": {
      "svg": { "attributes": ["xmlns", "width", "height", "viewBox"], "root": true },
      "g": { "attributes": [] },
      "defs": { "attributes": [], "hidden": true },
      "title": { "attributes": ["lang"], "hidden": true },
      "desc": { "attributes": ["lang"], "hidden": true },
      "metadata": { "attributes": ["id"], "hidden": true },
      "path": { "attributes": ["d"], "drawn": true },
      "rect": { "attributes": ["x", "y", "width", "height", "rx", "ry"], "drawn": true },
      "circle": { "attributes": ["cx", "cy", "r"], "drawn": true },
      "ellipse": { "attributes": ["cx", "cy", "rx", "ry"], "drawn": true },
      "line": { "attributes": ["x1", "y1", "x2", "y2"], "drawn": true },
      "polyline": { "attributes": ["points"], "drawn": true },
      "polygon": { "attributes": ["points"], "drawn": true },
      "text": { "attributes": ["x", "y", "dx", "dy", "xml:space"], "drawn": true },
      "tspan": { "attributes": ["x", "y", "dx", "dy", "xml:space"] },
      "use": { "attributes": ["href", "x", "y"], "drawn": true },
      "image": { "attributes": ["href", "x", "y", "width", "height", "preserveAspectRatio"], "drawn": true, "picture": true },
      "pattern": { "attributes": ["x", "y", "width", "height", "patternUnits", "patternContentUnits", "patternTransform", "viewBox"], "hidden": true },
      "clipPath": { "attributes": ["clipPathUnits"], "hidden": true },
      "marker": { "attributes": ["markerWidth", "markerHeight", "markerUnits", "refX", "refY", "orient", "viewBox"], "hidden": true }
    },
    "anyElement": [
      "id", "class", "role", "aria-label", "transform", "clip-path", "opacity", "fill", "fill-opacity", "fill-rule", "stroke", "stroke-width",
      "stroke-opacity", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-dasharray", "stroke-dashoffset", "marker-start", "marker-mid",
      "marker-end", "font-family", "font-size", "font-weight", "font-style", "text-anchor"
    ],
    "notOnRoot": ["transform"],
    "modelLink": [
      "data-eik-layer", "data-eik-viewport", "data-eik-view", "data-eik-id", "data-eik-part", "data-eik-record", "data-eik-role", "data-eik-feature",
      "data-eik-hash", "data-eik-item", "data-eik-ref", "data-eik-origin", "data-eik-anchor", "data-eik-rev", "data-eik-change", "data-eik-code"
    ],
    "extensionData": {
      "form": "data-<prefix>-<name>",
      "note": "A data attribute under an extension prefix registered in the extension registry (Part I, 11.1) is allowed and ignored (outline, section D, item 10). The prefix must be registered: a validator that is not given the registered prefixes allows none. Every other data-* attribute is refused."
    },
    "forbiddenElements": {
      "script": "script runs",
      "foreignObject": "it carries HTML, which can run script",
      "style": "CSS: imports, fetches and rules a renderer applies differently",
      "symbol": "SVG 1.1 and SVG 2 size it differently: use a g and use",
      "filter": "a filter; engines draw them differently",
      "mask": "a mask",
      "linearGradient": "a gradient",
      "radialGradient": "a gradient",
      "meshgradient": "a gradient",
      "hatch": "an SVG 2 hatch, deferred by the SVG working group: use a pattern",
      "hatchpath": "an SVG 2 hatch, deferred by the SVG working group: use a pattern",
      "solidcolor": "an SVG 2 paint server",
      "animate": "animation",
      "animateMotion": "animation",
      "animateTransform": "animation",
      "animateColor": "animation",
      "set": "animation",
      "mpath": "animation",
      "discard": "animation",
      "a": "a link",
      "switch": "a switch: what is drawn depends on the renderer",
      "view": "a view of the file, a link target",
      "textPath": "text on a path, which engines lay out differently",
      "font": "an SVG font, which SVG 2 removed",
      "font-face": "an SVG font, which SVG 2 removed",
      "cursor": "interactivity",
      "iframe": "embedded content",
      "video": "embedded content",
      "audio": "embedded content",
      "canvas": "embedded content",
      "svg": "a nested svg: only the root is an svg"
    },
    "picture": {
      "element": "image",
      "layer": "derived",
      "viewKinds": ["3d"],
      "role": "picture",
      "sheetLayer": "sheet",
      "sheetMediaTypes": ["image/png", "image/jpeg"],
      "note": "By the steward's decision of 16 October 2026 (outline, section E, item 7), image is allowed as the picture of a 3D view: the one child of the derived layer of the viewport group of a view whose kind is one of viewKinds (the derivation's viewport gives it), its href data of image/png in base64 (references, image/href). By the steward's decision of 19 October 2026, image is also allowed anywhere in the sheet layer (sheetLayer): a title block's logo, or a picture placed on the sheet, its href data of one of sheetMediaTypes in base64. Either carries data-eik-role picture and no data-eik-id, data-eik-record or data-eik-item, never a file or a URL. An image anywhere else, a second picture of a 3D view and anything beside it in its layer are refused (rule 8). A picture names no element, which rule 19 does not ask of it, and counts towards the 64 MiB."
    },
    "forbiddenElementPrefixes": {
      "fe": "a filter primitive"
    },
    "forbiddenAttributes": {
      "on*": "an event handler: script",
      "style": "CSS",
      "vector-effect": "it ties widths to the screen, not the paper",
      "xlink:*": "SVG 1.1's links: the profile writes href",
      "xml:base": "a base for references outside the file",
      "display": "hides or shows by CSS",
      "visibility": "hides or shows by CSS",
      "pointer-events": "interactivity",
      "data-*": "a data attribute that is not one of the model link (6.8) nor under a registered extension prefix",
      "<prefix>:*": "an attribute in another namespace"
    },
    "values": {
      "xmlns": { "type": "namespace", "rule": 5 },
      "svg/width": { "type": "paper", "rule": 6 },
      "svg/height": { "type": "paper", "rule": 6 },
      "viewBox": { "type": "viewBox" },
      "id": { "type": "nonEmpty" },
      "class": { "type": "text" },
      "role": { "type": "text" },
      "aria-label": { "type": "text" },
      "lang": { "type": "text" },
      "transform": { "type": "transform" },
      "patternTransform": { "type": "transform" },
      "clip-path": { "type": "url", "kinds": ["clipPath"], "none": true },
      "marker-start": { "type": "url", "kinds": ["marker"], "none": true },
      "marker-mid": { "type": "url", "kinds": ["marker"], "none": true },
      "marker-end": { "type": "url", "kinds": ["marker"], "none": true },
      "fill": { "type": "paint", "kinds": ["pattern"] },
      "stroke": { "type": "paint", "kinds": ["pattern"] },
      "opacity": { "type": "number", "min": 0, "max": 1 },
      "fill-opacity": { "type": "number", "min": 0, "max": 1 },
      "stroke-opacity": { "type": "number", "min": 0, "max": 1 },
      "fill-rule": { "type": "enum", "values": ["nonzero", "evenodd"] },
      "stroke-width": { "type": "number", "min": 0 },
      "stroke-linecap": { "type": "enum", "values": ["butt", "round", "square"] },
      "stroke-linejoin": { "type": "enum", "values": ["miter", "round", "bevel"] },
      "stroke-miterlimit": { "type": "number", "min": 1 },
      "stroke-dasharray": { "type": "dasharray" },
      "stroke-dashoffset": { "type": "number" },
      "font-family": { "type": "family", "rule": 16 },
      "font-size": { "type": "number", "min": 0 },
      "font-weight": { "type": "enum", "values": ["normal", "bold", "100", "200", "300", "400", "500", "600", "700", "800", "900"] },
      "font-style": { "type": "enum", "values": ["normal", "italic", "oblique"] },
      "text-anchor": { "type": "enum", "values": ["start", "middle", "end"] },
      "x": { "type": "number" },
      "y": { "type": "number" },
      "width": { "type": "number", "min": 0 },
      "height": { "type": "number", "min": 0 },
      "rx": { "type": "number", "min": 0 },
      "ry": { "type": "number", "min": 0 },
      "cx": { "type": "number" },
      "cy": { "type": "number" },
      "r": { "type": "number", "min": 0 },
      "x1": { "type": "number" },
      "y1": { "type": "number" },
      "x2": { "type": "number" },
      "y2": { "type": "number" },
      "points": { "type": "numbers", "even": true, "least": 2 },
      "d": { "type": "path" },
      "text/x": { "type": "numbers", "least": 1 },
      "text/y": { "type": "numbers", "least": 1 },
      "text/dx": { "type": "numbers", "least": 1 },
      "text/dy": { "type": "numbers", "least": 1 },
      "tspan/x": { "type": "numbers", "least": 1 },
      "tspan/y": { "type": "numbers", "least": 1 },
      "tspan/dx": { "type": "numbers", "least": 1 },
      "tspan/dy": { "type": "numbers", "least": 1 },
      "xml:space": { "type": "enum", "values": ["preserve"] },
      "use/href": { "type": "reference", "rule": 12 },
      "image/href": { "type": "reference", "rule": 12 },
      "patternUnits": { "type": "enum", "values": ["userSpaceOnUse", "objectBoundingBox"] },
      "patternContentUnits": { "type": "enum", "values": ["userSpaceOnUse", "objectBoundingBox"] },
      "clipPathUnits": { "type": "enum", "values": ["userSpaceOnUse", "objectBoundingBox"] },
      "markerUnits": { "type": "enum", "values": ["strokeWidth", "userSpaceOnUse"] },
      "markerWidth": { "type": "number", "min": 0 },
      "markerHeight": { "type": "number", "min": 0 },
      "refX": { "type": "number" },
      "refY": { "type": "number" },
      "orient": { "type": "orient" },
      "preserveAspectRatio": { "type": "enum", "values": ["none", "xMidYMid meet", "xMidYMid slice"] },
      "data-eik-layer": { "type": "enum", "values": ["sheet", "derived", "drafted", "agent", "revisions"], "rule": 17 },
      "data-eik-viewport": { "type": "nonEmpty", "rule": 24 },
      "data-eik-view": { "type": "nonEmpty", "rule": 24 },
      "data-eik-id": { "type": "ids", "ascending": true },
      "data-eik-part": { "type": "pattern", "pattern": "^(?:0|[1-9][0-9]*)$", "rule": 20 },
      "data-eik-record": { "type": "pattern", "pattern": "^[a-z][A-Za-z0-9]*/[^/]+$" },
      "data-eik-role": { "type": "enum", "values": ["cut", "poche", "projection", "hidden", "overhead", "beyond", "hatch", "symbol", "text", "picture"] },
      "data-eik-feature": { "type": "pattern", "pattern": "^(?:layer|face|edge):\\S+$" },
      "data-eik-hash": { "type": "pattern", "pattern": "^[0-9a-f]{64}$", "rule": 22 },
      "data-eik-item": { "type": "nonEmpty", "rule": 23 },
      "data-eik-ref": { "type": "ids" },
      "data-eik-origin": { "type": "enum", "values": ["derived", "person", "agent"], "rule": 23 },
      "data-eik-anchor": { "type": "enum", "values": ["attached", "moved", "elementOnly", "orphaned"], "rule": 27 },
      "data-eik-rev": { "type": "text" },
      "data-eik-change": { "type": "ids" },
      "data-eik-code": { "type": "pattern", "pattern": "^[0-9a-f]{64}$" }
    },
    "references": {
      "use/href": {
        "form": "fragment",
        "kinds": ["g", "path", "rect", "circle", "ellipse", "line", "polyline", "polygon", "text", "use"],
        "note": "href is only on use, as #<id> of an element of these kinds; nothing outside the file. A reference of the form data names data of one of mediaTypes in base64 instead, which no element of profile 0.1 takes."
      },
      "image/href": {
        "form": "data",
        "mediaTypes": ["image/png"],
        "signatures": { "image/png": "89504e470d0a1a0a", "image/jpeg": "ffd8ff" },
        "note": "a picture (picture): the picture of a 3D view data:image/png;base64, and one of the sheet layer also data:image/jpeg;base64 (picture, sheetMediaTypes), with valid base64 of a PNG or a JPEG (its first bytes the format's signature, in hexadecimal here); never a file, a URL or another media type"
      },
      "url()": {
        "form": "url",
        "note": "url(#<id>) only in clip-path, marker-start, marker-mid, marker-end, fill and stroke, each naming an element of the kinds its entry in values gives; nothing outside the file"
      }
    },
    "transforms": ["matrix", "translate", "scale", "rotate"],
    "colours": {
      "keywords": ["none"],
      "pattern": "^#[0-9a-f]{6}$",
      "note": "none, #rrggbb in lower case, or url(#<id>) of a pattern"
    },
    "layers": {
      "root": ["title", "desc", "metadata", "defs", "sheet", "viewport", "sheet", "revisions"],
      "once": ["title", "desc", "metadata", "defs", "sheet", "revisions"],
      "required": ["title", "metadata", "sheet"],
      "note": "root lists the root's children in their order (6.7). A kind listed twice stands at either of its places, and a kind of once occurs at most once: so the sheet layer comes before the viewport groups, or after them and before the revisions layer, by the steward's decision of 17 October 2026, and never twice. viewport lists a viewport group's layers in their order. Where the derivation's generator.order is paint, an element may have several groups in a derived layer, its parts, each with data-eik-part numbered from 0 in the order of the file (6.7; 6.12, rule 20).",
      "viewport": ["derived", "drafted", "agent"],
      "origins": { "derived": "derived", "drafted": "person", "agent": "agent" },
      "anchors": ["attached", "moved", "elementOnly", "orphaned"]
    },
    "derivation": {
      "metadataId": "openeik-derivation",
      "format": "openeik-drawing-derivation/0.1",
      "orders": ["id", "paint"],
      "viewKinds": ["plan", "section", "elevation", "3d", "drafting"],
      "unscaled": ["3d"]
    }
  }
}
