@dicebear/schema 0.10.1 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,44 +1,52 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "definitions": {
4
- "identifier": {
5
- "description": "A camelCase identifier starting with a lowercase letter. Used for component, variable, and color references.",
4
+ "camelCaseName": {
5
+ "description": "A camelCase identifier used for named things defined in the definition (colors, components, variants). Must start with a lowercase letter and may contain letters and digits.",
6
6
  "type": "string",
7
- "pattern": "^[a-z][a-zA-Z0-9]*$"
7
+ "pattern": "^[a-z][a-zA-Z0-9]*$",
8
+ "maxLength": 64
8
9
  },
9
- "colorAttribute": {
10
- "description": "A color value, either as a direct color string (named color, hex, rgb(a), hsl(a), hsb(a)) or as a reference to a named color defined in the `colors` section.",
10
+ "colorName": {
11
+ "description": "A reference to a color palette defined in the top-level `colors` section.",
12
+ "allOf": [{ "$ref": "#/definitions/camelCaseName" }]
13
+ },
14
+ "componentName": {
15
+ "description": "A reference to a component defined in the top-level `components` section.",
16
+ "allOf": [{ "$ref": "#/definitions/camelCaseName" }]
17
+ },
18
+ "translateValue": {
19
+ "description": "A translation value expressed as a percentage of the component's width (for `x`) or height (for `y`). A single value fixes the translation; two values define a range the PRNG picks from.",
20
+ "type": "array",
21
+ "items": {
22
+ "type": "number",
23
+ "minimum": -1000,
24
+ "maximum": 1000
25
+ },
26
+ "minItems": 1,
27
+ "maxItems": 2
28
+ },
29
+ "hexColor": {
30
+ "description": "A hex color with leading `#`, in 3, 4, 6, or 8 digit form.",
31
+ "type": "string",
32
+ "pattern": "^#([a-fA-F0-9]{3}|[a-fA-F0-9]{4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$",
33
+ "maxLength": 9
34
+ },
35
+ "colorValue": {
36
+ "description": "A color value for `fill`, `stroke`, `stop-color`, and other color attributes. Either a plain string (any CSS color format — named color, hex, `rgb()`, `oklch()`, `color-mix()`, local paint server reference `url(#id)`, etc.) or an object referencing a named color palette defined in the top-level `colors` section. CSS color syntax is not validated; invalid colors are the browser's problem.",
11
37
  "anyOf": [
38
+ { "$ref": "#/definitions/attributeString" },
12
39
  {
13
- "type": "string",
14
- "anyOf": [
15
- { "pattern": "^[a-zA-Z]+$" },
16
- { "pattern": "^#([a-fA-F0-9]{3}|[a-fA-F0-9]{4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$" },
17
- {
18
- "pattern": "^rgba?\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*(,\\s*[0-1](\\.\\d+)?\\s*)?\\)$"
19
- },
20
- {
21
- "pattern": "^hsla?\\(\\s*\\d+\\s*,\\s*\\d+%\\s*,\\s*\\d+%\\s*(,\\s*[0-1](\\.\\d+)?\\s*)?\\)$"
22
- },
23
- {
24
- "pattern": "^hsba?\\(\\s*\\d+\\s*,\\s*\\d+%\\s*,\\s*\\d+%\\s*(,\\s*[0-1](\\.\\d+)?\\s*)?\\)$"
25
- }
26
- ]
27
- },
28
- {
29
- "description": "A reference to a named color. At render time, the PRNG selects a color value from the referenced color.",
40
+ "description": "A reference to a named color palette. At render time, the PRNG selects a color value from the referenced palette.",
30
41
  "type": "object",
31
42
  "properties": {
32
- "type": {
33
- "type": "string",
34
- "const": "color"
35
- },
36
- "value": {
37
- "description": "The name of the color to reference.",
38
- "$ref": "#/definitions/identifier"
43
+ "type": { "const": "color" },
44
+ "name": {
45
+ "description": "The name of the color palette to reference.",
46
+ "$ref": "#/definitions/colorName"
39
47
  }
40
48
  },
41
- "required": ["type", "value"],
49
+ "required": ["type", "name"],
42
50
  "additionalProperties": false
43
51
  }
44
52
  ]
@@ -46,45 +54,134 @@
46
54
  "safeUrl": {
47
55
  "description": "A URL restricted to HTTP and HTTPS protocols.",
48
56
  "type": "string",
49
- "pattern": "^https?://"
57
+ "pattern": "^https?://",
58
+ "maxLength": 2048
50
59
  },
51
- "paintAttribute": {
52
- "description": "A paint value for `fill` and `stroke` attributes. Accepts all color formats from `colorAttribute` as well as local SVG paint server references in the form `url(#id)`, e.g. for gradients or patterns.",
53
- "anyOf": [
54
- { "$ref": "#/definitions/colorAttribute" },
55
- { "type": "string", "pattern": "^url\\(#[a-zA-Z_][a-zA-Z0-9_.-]*\\)$" }
56
- ]
57
- },
58
- "noExternalUrlRef": {
59
- "description": "A string that must not contain external URL references (e.g. `url(https://...)`) or CSS escape sequences (backslash). Local references such as `url(#id)` are permitted.",
60
+ "filteredString": {
61
+ "description": "Base definition for the filtered-string family (`attributeString`, `cssString`). Blocks a shared set of known-dangerous patterns: external `url(...)` references (local `url(#id)` is allowed), `expression()`, `behavior:`, `-moz-binding`, `javascript:` / `vbscript:` URI schemes, and backslash escape sequences. This is not a general CSS sanitizer — it is a defense-in-depth injection filter, so substring matches of blocked tokens will reject otherwise-harmless strings (e.g. a plain text containing the literal word `javascript:`). The `maxLength` here acts as an absolute ceiling for all derivatives; callers narrow it further.",
60
62
  "type": "string",
63
+ "maxLength": 16384,
61
64
  "not": {
65
+ "type": "string",
62
66
  "anyOf": [
63
- { "pattern": "[uU][rR][lL]\\s*\\(\\s*[^#)]" },
64
- { "pattern": "\\\\" }
67
+ { "type": "string", "pattern": "[uU][rR][lL]\\s*\\(\\s*[^#)\\s]" },
68
+ {
69
+ "type": "string",
70
+ "pattern": "[eE][xX][pP][rR][eE][sS][sS][iI][oO][nN]\\s*\\("
71
+ },
72
+ {
73
+ "type": "string",
74
+ "pattern": "[bB][eE][hH][aA][vV][iI][oO][rR]\\s*:"
75
+ },
76
+ {
77
+ "type": "string",
78
+ "pattern": "-[mM][oO][zZ]-[bB][iI][nN][dD][iI][nN][gG]"
79
+ },
80
+ {
81
+ "type": "string",
82
+ "pattern": "[jJ][aA][vV][aA][sS][cC][rR][iI][pP][tT]\\s*:"
83
+ },
84
+ {
85
+ "type": "string",
86
+ "pattern": "[vV][bB][sS][cC][rR][iI][pP][tT]\\s*:"
87
+ },
88
+ { "type": "string", "pattern": "\\\\" }
65
89
  ]
66
90
  }
67
91
  },
68
- "noCssInjection": {
69
- "description": "A string that must not contain CSS injection patterns, including `@`-rules, `expression()`, `behavior:`, or `-moz-binding`.",
92
+ "attributeString": {
93
+ "description": "The default value type for generic SVG attribute values — transform lists, numeric values, keywords, and so on. No syntactic validation; only the common `filteredString` injection filter applies.",
70
94
  "type": "string",
71
- "not": {
72
- "anyOf": [
73
- { "pattern": "@" },
74
- { "pattern": "[eE][xX][pP][rR][eE][sS][sS][iI][oO][nN]\\s*\\(" },
75
- { "pattern": "[bB][eE][hH][aA][vV][iI][oO][rR]\\s*:" },
76
- { "pattern": "-[mM][oO][zZ]-[bB][iI][nN][dD][iI][nN][gG]" },
77
- { "pattern": "\\\\" }
78
- ]
79
- }
95
+ "allOf": [{ "$ref": "#/definitions/filteredString" }],
96
+ "maxLength": 1024
97
+ },
98
+ "pathDataString": {
99
+ "description": "Used for the `d` attribute of `<path>`. Same filter as `attributeString`, but with a much larger length budget to accommodate complex path geometry.",
100
+ "type": "string",
101
+ "allOf": [{ "$ref": "#/definitions/filteredString" }],
102
+ "maxLength": 16384
103
+ },
104
+ "cssString": {
105
+ "description": "Used for inline `style` attribute content and `<style>` element bodies. `@`-rules (`@import`, `@font-face`, `@keyframes`, etc.) are rejected in addition to the common `filteredString` injection filter. This is not a general CSS sanitizer.",
106
+ "type": "string",
107
+ "allOf": [{ "$ref": "#/definitions/filteredString" }],
108
+ "maxLength": 4096,
109
+ "not": { "type": "string", "pattern": "@" }
80
110
  },
81
111
  "element": {
82
- "description": "An SVG node. Can be an actual SVG element (`element`), a raw text node (`text`), or a reference to a named component (`component`).",
112
+ "description": "An SVG node. One of four mutually exclusive forms, discriminated by `type` (and `name` for the `<style>` special case): a text element, a component reference, a `<style>` element, or any other SVG element.",
113
+ "anyOf": [
114
+ { "$ref": "#/definitions/textElement" },
115
+ { "$ref": "#/definitions/componentReference" },
116
+ { "$ref": "#/definitions/styleElement" },
117
+ { "$ref": "#/definitions/genericElement" }
118
+ ]
119
+ },
120
+ "textElement": {
121
+ "description": "A raw text node. Its `value` becomes the text content rendered into the parent element.",
83
122
  "type": "object",
84
123
  "properties": {
124
+ "type": { "const": "text" },
125
+ "value": {
126
+ "description": "Either a plain string, or a `variable` reference resolved at render time to the seed's initials.",
127
+ "anyOf": [
128
+ { "type": "string", "maxLength": 4096 },
129
+ {
130
+ "type": "object",
131
+ "properties": {
132
+ "type": { "const": "variable" },
133
+ "name": { "enum": ["initial", "initials"] }
134
+ },
135
+ "required": ["type", "name"],
136
+ "additionalProperties": false
137
+ }
138
+ ]
139
+ }
140
+ },
141
+ "required": ["type", "value"],
142
+ "additionalProperties": false
143
+ },
144
+ "componentReference": {
145
+ "description": "A reference to a named component defined in the top-level `components` section. At render time, the PRNG selects one of the component's variants.",
146
+ "type": "object",
147
+ "properties": {
148
+ "type": { "const": "component" },
149
+ "name": { "$ref": "#/definitions/componentName" }
150
+ },
151
+ "required": ["type", "name"],
152
+ "additionalProperties": false
153
+ },
154
+ "styleElement": {
155
+ "description": "An SVG `<style>` element. Its CSS content must be provided as `text` children; each child's value is validated as a CSS string with a stricter content policy than generic SVG attribute values.",
156
+ "type": "object",
157
+ "properties": {
158
+ "type": { "const": "element" },
159
+ "name": { "const": "style" },
160
+ "attributes": { "$ref": "#/definitions/attributes" },
161
+ "children": {
162
+ "type": "array",
163
+ "items": {
164
+ "type": "object",
165
+ "properties": {
166
+ "type": { "const": "text" },
167
+ "value": { "$ref": "#/definitions/cssString" }
168
+ },
169
+ "required": ["type", "value"],
170
+ "additionalProperties": false
171
+ },
172
+ "maxItems": 64
173
+ }
174
+ },
175
+ "required": ["type", "name"],
176
+ "additionalProperties": false
177
+ },
178
+ "genericElement": {
179
+ "description": "Any SVG element other than `<style>`, which has its own stricter content policy.",
180
+ "type": "object",
181
+ "properties": {
182
+ "type": { "const": "element" },
85
183
  "name": {
86
184
  "description": "The SVG tag name. Only a safe subset of SVG elements is permitted; dangerous elements such as `script`, `foreignObject`, or `a` are excluded.",
87
- "type": "string",
88
185
  "enum": [
89
186
  "circle",
90
187
  "clipPath",
@@ -132,7 +229,6 @@
132
229
  "radialGradient",
133
230
  "rect",
134
231
  "stop",
135
- "style",
136
232
  "svg",
137
233
  "switch",
138
234
  "symbol",
@@ -144,313 +240,215 @@
144
240
  "view"
145
241
  ]
146
242
  },
147
- "type": {
148
- "description": "The node type. `element` renders an SVG tag, `text` renders a raw text node, `component` inserts a named component by reference.",
149
- "type": "string",
150
- "enum": ["element", "text", "component"]
151
- },
152
- "value": {
153
- "description": "The text content for `text` nodes, the component name for `component` nodes, or the CSS content for `style` elements.",
154
- "anyOf": [
155
- { "type": "string" },
156
- {
157
- "type": "object",
158
- "properties": {
159
- "type": { "type": "string", "const": "variable" },
160
- "value": { "type": "string", "enum": ["initial", "initials"] }
161
- },
162
- "required": ["type", "value"],
163
- "additionalProperties": false
164
- }
165
- ]
166
- },
167
- "attributes": {
168
- "description": "SVG presentation attributes to apply to this element.",
169
- "$ref": "#/definitions/attributes"
170
- },
243
+ "attributes": { "$ref": "#/definitions/attributes" },
171
244
  "children": {
172
- "description": "Nested child elements. Only valid for `element` and `text` nodes.",
173
245
  "type": "array",
174
- "items": {
175
- "$ref": "#/definitions/element"
176
- }
246
+ "items": { "$ref": "#/definitions/element" },
247
+ "maxItems": 1024
177
248
  }
178
249
  },
179
- "required": ["type"],
180
- "additionalProperties": false,
181
- "allOf": [
182
- {
183
- "if": {
184
- "properties": { "type": { "const": "component" } },
185
- "required": ["type"]
186
- },
187
- "then": {
188
- "required": ["value"],
189
- "properties": { "value": { "$ref": "#/definitions/identifier" } },
190
- "not": { "required": ["children"] }
191
- }
192
- },
193
- {
194
- "if": {
195
- "properties": { "type": { "const": "element" } },
196
- "required": ["type"]
197
- },
198
- "then": {
199
- "required": ["name"],
200
- "if": {
201
- "properties": { "name": { "const": "style" } }
202
- },
203
- "then": {
204
- "properties": {
205
- "value": {
206
- "allOf": [
207
- { "$ref": "#/definitions/noExternalUrlRef" },
208
- { "$ref": "#/definitions/noCssInjection" }
209
- ]
210
- }
211
- }
212
- },
213
- "else": {
214
- "not": { "required": ["value"] }
215
- }
216
- }
217
- }
218
- ]
250
+ "required": ["type", "name"],
251
+ "additionalProperties": false
219
252
  },
220
253
  "attributes": {
221
254
  "description": "A map of allowed SVG presentation attributes. Only a safe subset is permitted; event handlers (e.g. `onclick`) and namespace attributes (e.g. `xlink:href`) are not allowed.",
222
255
  "type": "object",
223
256
  "properties": {
224
- "alignment-baseline": { "type": "string" },
225
- "amplitude": { "type": "string" },
226
- "azimuth": { "type": "string" },
227
- "baseFrequency": { "type": "string" },
228
- "baseline-shift": { "type": "string" },
229
- "bias": { "type": "string" },
230
- "class": {
231
- "description": "CSS class name(s). Only alphanumeric characters, underscores, hyphens, and spaces are allowed.",
232
- "type": "string",
233
- "pattern": "^[a-zA-Z0-9_ -]+$"
234
- },
235
- "clipPathUnits": { "type": "string" },
236
- "clip-path": {
237
- "description": "References a clip path. External URL references are not allowed.",
238
- "$ref": "#/definitions/noExternalUrlRef"
239
- },
240
- "clip-rule": { "type": "string" },
257
+ "alignment-baseline": { "$ref": "#/definitions/attributeString" },
258
+ "amplitude": { "$ref": "#/definitions/attributeString" },
259
+ "azimuth": { "$ref": "#/definitions/attributeString" },
260
+ "baseFrequency": { "$ref": "#/definitions/attributeString" },
261
+ "baseline-shift": { "$ref": "#/definitions/attributeString" },
262
+ "bias": { "$ref": "#/definitions/attributeString" },
263
+ "class": { "$ref": "#/definitions/attributeString" },
264
+ "clipPathUnits": { "$ref": "#/definitions/attributeString" },
265
+ "clip-path": { "$ref": "#/definitions/attributeString" },
266
+ "clip-rule": { "$ref": "#/definitions/attributeString" },
241
267
  "color": {
242
- "$ref": "#/definitions/colorAttribute"
268
+ "$ref": "#/definitions/colorValue"
243
269
  },
244
- "color-interpolation": { "type": "string" },
245
- "color-interpolation-filters": { "type": "string" },
246
- "crossorigin": { "type": "string" },
247
- "cx": { "type": "string" },
248
- "cy": { "type": "string" },
249
- "d": { "type": "string" },
250
- "decoding": { "type": "string" },
251
- "diffuseConstant": { "type": "string" },
252
- "direction": { "type": "string" },
253
- "display": { "type": "string" },
254
- "divisor": { "type": "string" },
255
- "dx": { "type": "string" },
256
- "dy": { "type": "string" },
257
- "edgeMode": { "type": "string" },
258
- "elevation": { "type": "string" },
259
- "exponent": { "type": "string" },
260
- "fill": {
261
- "description": "The fill color or paint server reference for this element.",
262
- "$ref": "#/definitions/paintAttribute"
270
+ "color-interpolation": { "$ref": "#/definitions/attributeString" },
271
+ "color-interpolation-filters": {
272
+ "$ref": "#/definitions/attributeString"
263
273
  },
264
- "fill-opacity": { "type": "string" },
265
- "fill-rule": { "type": "string" },
266
- "filter": {
267
- "description": "References a filter effect. External URL references are not allowed.",
268
- "$ref": "#/definitions/noExternalUrlRef"
269
- },
270
- "filterUnits": { "type": "string" },
274
+ "crossorigin": { "$ref": "#/definitions/attributeString" },
275
+ "cx": { "$ref": "#/definitions/attributeString" },
276
+ "cy": { "$ref": "#/definitions/attributeString" },
277
+ "d": { "$ref": "#/definitions/pathDataString" },
278
+ "decoding": { "$ref": "#/definitions/attributeString" },
279
+ "diffuseConstant": { "$ref": "#/definitions/attributeString" },
280
+ "direction": { "$ref": "#/definitions/attributeString" },
281
+ "display": { "$ref": "#/definitions/attributeString" },
282
+ "divisor": { "$ref": "#/definitions/attributeString" },
283
+ "dx": { "$ref": "#/definitions/attributeString" },
284
+ "dy": { "$ref": "#/definitions/attributeString" },
285
+ "edgeMode": { "$ref": "#/definitions/attributeString" },
286
+ "elevation": { "$ref": "#/definitions/attributeString" },
287
+ "exponent": { "$ref": "#/definitions/attributeString" },
288
+ "fill": { "$ref": "#/definitions/colorValue" },
289
+ "fill-opacity": { "$ref": "#/definitions/attributeString" },
290
+ "fill-rule": { "$ref": "#/definitions/attributeString" },
291
+ "filter": { "$ref": "#/definitions/attributeString" },
292
+ "filterUnits": { "$ref": "#/definitions/attributeString" },
271
293
  "flood-color": {
272
- "$ref": "#/definitions/colorAttribute"
294
+ "$ref": "#/definitions/colorValue"
273
295
  },
274
- "flood-opacity": { "type": "string" },
296
+ "flood-opacity": { "$ref": "#/definitions/attributeString" },
275
297
  "font-family": {
276
298
  "anyOf": [
277
- { "type": "string" },
299
+ { "$ref": "#/definitions/attributeString" },
278
300
  {
279
301
  "type": "object",
280
302
  "properties": {
281
- "type": { "type": "string", "const": "variable" },
282
- "value": { "type": "string", "enum": ["fontFamily"] }
303
+ "type": { "const": "variable" },
304
+ "name": { "const": "fontFamily" }
283
305
  },
284
- "required": ["type", "value"],
306
+ "required": ["type", "name"],
285
307
  "additionalProperties": false
286
308
  }
287
309
  ]
288
310
  },
289
- "font-size": { "type": "string" },
290
- "font-size-adjust": { "type": "string" },
291
- "font-style": { "type": "string" },
292
- "font-variant": { "type": "string" },
311
+ "font-size": { "$ref": "#/definitions/attributeString" },
312
+ "font-size-adjust": { "$ref": "#/definitions/attributeString" },
313
+ "font-style": { "$ref": "#/definitions/attributeString" },
314
+ "font-variant": { "$ref": "#/definitions/attributeString" },
293
315
  "font-weight": {
294
316
  "anyOf": [
295
- { "type": "string" },
317
+ { "$ref": "#/definitions/attributeString" },
296
318
  {
297
319
  "type": "object",
298
320
  "properties": {
299
- "type": { "type": "string", "const": "variable" },
300
- "value": { "type": "string", "enum": ["fontWeight"] }
321
+ "type": { "const": "variable" },
322
+ "name": { "const": "fontWeight" }
301
323
  },
302
- "required": ["type", "value"],
324
+ "required": ["type", "name"],
303
325
  "additionalProperties": false
304
326
  }
305
327
  ]
306
328
  },
307
- "fx": { "type": "string" },
308
- "fy": { "type": "string" },
309
- "gradientTransform": { "type": "string" },
310
- "gradientUnits": { "type": "string" },
311
- "height": { "type": "string" },
329
+ "fx": { "$ref": "#/definitions/attributeString" },
330
+ "fy": { "$ref": "#/definitions/attributeString" },
331
+ "gradientTransform": { "$ref": "#/definitions/attributeString" },
332
+ "gradientUnits": { "$ref": "#/definitions/attributeString" },
333
+ "height": { "$ref": "#/definitions/attributeString" },
312
334
  "href": {
313
- "description": "A hyperlink reference. Only local fragment references (`#id`) and safe data URIs (raster images) are allowed.",
314
335
  "anyOf": [
315
336
  {
316
337
  "type": "string",
317
- "pattern": "^#[a-zA-Z0-9-]+$"
338
+ "pattern": "^#[a-zA-Z_][a-zA-Z0-9_.-]*$",
339
+ "maxLength": 128
318
340
  },
319
341
  {
320
342
  "type": "string",
321
- "pattern": "^data:image/(png|gif|jpg|jpeg|webp|avif);base64,[a-zA-Z0-9+/=]+$"
343
+ "pattern": "^data:image/(png|gif|jpeg|webp|avif);base64,[a-zA-Z0-9+/=]+$",
344
+ "maxLength": 262144
322
345
  }
323
346
  ]
324
347
  },
325
- "id": {
326
- "description": "A unique identifier for the element. Must start with a letter or underscore.",
327
- "type": "string",
328
- "pattern": "^[a-zA-Z_][a-zA-Z0-9_.-]*$"
329
- },
330
- "image-rendering": { "type": "string" },
331
- "in": { "type": "string" },
332
- "in2": { "type": "string" },
333
- "intercept": { "type": "string" },
334
- "k1": { "type": "string" },
335
- "k2": { "type": "string" },
336
- "k3": { "type": "string" },
337
- "k4": { "type": "string" },
338
- "kernelMatrix": { "type": "string" },
339
- "kernelUnitLength": { "type": "string" },
340
- "lang": { "type": "string" },
341
- "lengthAdjust": { "type": "string" },
342
- "letter-spacing": { "type": "string" },
348
+ "id": { "$ref": "#/definitions/attributeString" },
349
+ "image-rendering": { "$ref": "#/definitions/attributeString" },
350
+ "in": { "$ref": "#/definitions/attributeString" },
351
+ "in2": { "$ref": "#/definitions/attributeString" },
352
+ "intercept": { "$ref": "#/definitions/attributeString" },
353
+ "k1": { "$ref": "#/definitions/attributeString" },
354
+ "k2": { "$ref": "#/definitions/attributeString" },
355
+ "k3": { "$ref": "#/definitions/attributeString" },
356
+ "k4": { "$ref": "#/definitions/attributeString" },
357
+ "kernelMatrix": { "$ref": "#/definitions/attributeString" },
358
+ "kernelUnitLength": { "$ref": "#/definitions/attributeString" },
359
+ "lang": { "$ref": "#/definitions/attributeString" },
360
+ "lengthAdjust": { "$ref": "#/definitions/attributeString" },
361
+ "letter-spacing": { "$ref": "#/definitions/attributeString" },
343
362
  "lighting-color": {
344
- "$ref": "#/definitions/colorAttribute"
345
- },
346
- "marker-end": {
347
- "description": "References a marker to draw at the end of a path. External URL references are not allowed.",
348
- "$ref": "#/definitions/noExternalUrlRef"
349
- },
350
- "marker-mid": {
351
- "description": "References a marker to draw at intermediate vertices of a path. External URL references are not allowed.",
352
- "$ref": "#/definitions/noExternalUrlRef"
353
- },
354
- "marker-start": {
355
- "description": "References a marker to draw at the start of a path. External URL references are not allowed.",
356
- "$ref": "#/definitions/noExternalUrlRef"
363
+ "$ref": "#/definitions/colorValue"
357
364
  },
358
- "markerHeight": { "type": "string" },
359
- "markerUnits": { "type": "string" },
360
- "markerWidth": { "type": "string" },
361
- "mask": {
362
- "description": "References a mask element. External URL references are not allowed.",
363
- "$ref": "#/definitions/noExternalUrlRef"
364
- },
365
- "maskContentUnits": { "type": "string" },
366
- "maskUnits": { "type": "string" },
367
- "media": { "type": "string" },
368
- "method": { "type": "string" },
369
- "mode": { "type": "string" },
370
- "numOctaves": { "type": "string" },
371
- "offset": { "type": "string" },
372
- "opacity": { "type": "string" },
373
- "operator": { "type": "string" },
374
- "order": { "type": "string" },
375
- "orient": { "type": "string" },
376
- "overflow": { "type": "string" },
377
- "paint-order": { "type": "string" },
378
- "path": { "type": "string" },
379
- "pathLength": { "type": "string" },
380
- "patternContentUnits": { "type": "string" },
381
- "patternTransform": { "type": "string" },
382
- "patternUnits": { "type": "string" },
383
- "points": { "type": "string" },
384
- "preserveAlpha": { "type": "string" },
385
- "preserveAspectRatio": { "type": "string" },
386
- "primitiveUnits": { "type": "string" },
387
- "r": { "type": "string" },
388
- "radius": { "type": "string" },
389
- "refX": { "type": "string" },
390
- "refY": { "type": "string" },
391
- "result": { "type": "string" },
392
- "rx": { "type": "string" },
393
- "ry": { "type": "string" },
394
- "scale": { "type": "string" },
395
- "seed": { "type": "string" },
396
- "shape-rendering": { "type": "string" },
397
- "slope": { "type": "string" },
398
- "specularConstant": { "type": "string" },
399
- "specularExponent": { "type": "string" },
400
- "spreadMethod": { "type": "string" },
401
- "startOffset": { "type": "string" },
402
- "stdDeviation": { "type": "string" },
403
- "stitchTiles": { "type": "string" },
365
+ "marker-end": { "$ref": "#/definitions/attributeString" },
366
+ "marker-mid": { "$ref": "#/definitions/attributeString" },
367
+ "marker-start": { "$ref": "#/definitions/attributeString" },
368
+ "markerHeight": { "$ref": "#/definitions/attributeString" },
369
+ "markerUnits": { "$ref": "#/definitions/attributeString" },
370
+ "markerWidth": { "$ref": "#/definitions/attributeString" },
371
+ "mask": { "$ref": "#/definitions/attributeString" },
372
+ "maskContentUnits": { "$ref": "#/definitions/attributeString" },
373
+ "maskUnits": { "$ref": "#/definitions/attributeString" },
374
+ "media": { "$ref": "#/definitions/attributeString" },
375
+ "method": { "$ref": "#/definitions/attributeString" },
376
+ "mode": { "$ref": "#/definitions/attributeString" },
377
+ "numOctaves": { "$ref": "#/definitions/attributeString" },
378
+ "offset": { "$ref": "#/definitions/attributeString" },
379
+ "opacity": { "$ref": "#/definitions/attributeString" },
380
+ "operator": { "$ref": "#/definitions/attributeString" },
381
+ "order": { "$ref": "#/definitions/attributeString" },
382
+ "orient": { "$ref": "#/definitions/attributeString" },
383
+ "overflow": { "$ref": "#/definitions/attributeString" },
384
+ "paint-order": { "$ref": "#/definitions/attributeString" },
385
+ "path": { "$ref": "#/definitions/attributeString" },
386
+ "pathLength": { "$ref": "#/definitions/attributeString" },
387
+ "patternContentUnits": { "$ref": "#/definitions/attributeString" },
388
+ "patternTransform": { "$ref": "#/definitions/attributeString" },
389
+ "patternUnits": { "$ref": "#/definitions/attributeString" },
390
+ "points": { "$ref": "#/definitions/attributeString" },
391
+ "preserveAlpha": { "$ref": "#/definitions/attributeString" },
392
+ "preserveAspectRatio": { "$ref": "#/definitions/attributeString" },
393
+ "primitiveUnits": { "$ref": "#/definitions/attributeString" },
394
+ "r": { "$ref": "#/definitions/attributeString" },
395
+ "radius": { "$ref": "#/definitions/attributeString" },
396
+ "refX": { "$ref": "#/definitions/attributeString" },
397
+ "refY": { "$ref": "#/definitions/attributeString" },
398
+ "result": { "$ref": "#/definitions/attributeString" },
399
+ "rx": { "$ref": "#/definitions/attributeString" },
400
+ "ry": { "$ref": "#/definitions/attributeString" },
401
+ "scale": { "$ref": "#/definitions/attributeString" },
402
+ "seed": { "$ref": "#/definitions/attributeString" },
403
+ "shape-rendering": { "$ref": "#/definitions/attributeString" },
404
+ "slope": { "$ref": "#/definitions/attributeString" },
405
+ "specularConstant": { "$ref": "#/definitions/attributeString" },
406
+ "specularExponent": { "$ref": "#/definitions/attributeString" },
407
+ "spreadMethod": { "$ref": "#/definitions/attributeString" },
408
+ "startOffset": { "$ref": "#/definitions/attributeString" },
409
+ "stdDeviation": { "$ref": "#/definitions/attributeString" },
410
+ "stitchTiles": { "$ref": "#/definitions/attributeString" },
404
411
  "stop-color": {
405
- "$ref": "#/definitions/colorAttribute"
406
- },
407
- "stop-opacity": { "type": "string" },
408
- "stroke": {
409
- "description": "The stroke color or paint server reference for this element.",
410
- "$ref": "#/definitions/paintAttribute"
412
+ "$ref": "#/definitions/colorValue"
411
413
  },
412
- "stroke-dasharray": { "type": "string" },
413
- "stroke-dashoffset": { "type": "string" },
414
- "stroke-linecap": { "type": "string" },
415
- "stroke-linejoin": { "type": "string" },
416
- "stroke-miterlimit": { "type": "string" },
417
- "stroke-opacity": { "type": "string" },
418
- "stroke-width": { "type": "string" },
419
- "style": {
420
- "description": "Inline CSS styles. External URL references and CSS injection patterns are not allowed.",
421
- "allOf": [
422
- { "$ref": "#/definitions/noExternalUrlRef" },
423
- { "$ref": "#/definitions/noCssInjection" }
424
- ]
425
- },
426
- "surfaceScale": { "type": "string" },
427
- "systemLanguage": { "type": "string" },
428
- "tabindex": { "type": "string" },
429
- "tableValues": { "type": "string" },
430
- "targetX": { "type": "string" },
431
- "targetY": { "type": "string" },
432
- "text-anchor": { "type": "string" },
433
- "text-decoration": { "type": "string" },
434
- "text-rendering": { "type": "string" },
435
- "textLength": { "type": "string" },
436
- "transform": { "type": "string" },
437
- "transform-origin": { "type": "string" },
438
- "type": { "type": "string" },
439
- "values": { "type": "string" },
440
- "viewBox": { "type": "string" },
441
- "visibility": { "type": "string" },
442
- "width": { "type": "string" },
443
- "word-spacing": { "type": "string" },
444
- "writing-mode": { "type": "string" },
445
- "x": { "type": "string" },
446
- "x1": { "type": "string" },
447
- "x2": { "type": "string" },
448
- "xChannelSelector": { "type": "string" },
449
- "y": { "type": "string" },
450
- "y1": { "type": "string" },
451
- "y2": { "type": "string" },
452
- "yChannelSelector": { "type": "string" },
453
- "z": { "type": "string" }
414
+ "stop-opacity": { "$ref": "#/definitions/attributeString" },
415
+ "stroke": { "$ref": "#/definitions/colorValue" },
416
+ "stroke-dasharray": { "$ref": "#/definitions/attributeString" },
417
+ "stroke-dashoffset": { "$ref": "#/definitions/attributeString" },
418
+ "stroke-linecap": { "$ref": "#/definitions/attributeString" },
419
+ "stroke-linejoin": { "$ref": "#/definitions/attributeString" },
420
+ "stroke-miterlimit": { "$ref": "#/definitions/attributeString" },
421
+ "stroke-opacity": { "$ref": "#/definitions/attributeString" },
422
+ "stroke-width": { "$ref": "#/definitions/attributeString" },
423
+ "style": { "$ref": "#/definitions/cssString" },
424
+ "surfaceScale": { "$ref": "#/definitions/attributeString" },
425
+ "systemLanguage": { "$ref": "#/definitions/attributeString" },
426
+ "tabindex": { "$ref": "#/definitions/attributeString" },
427
+ "tableValues": { "$ref": "#/definitions/attributeString" },
428
+ "targetX": { "$ref": "#/definitions/attributeString" },
429
+ "targetY": { "$ref": "#/definitions/attributeString" },
430
+ "text-anchor": { "$ref": "#/definitions/attributeString" },
431
+ "text-decoration": { "$ref": "#/definitions/attributeString" },
432
+ "text-rendering": { "$ref": "#/definitions/attributeString" },
433
+ "textLength": { "$ref": "#/definitions/attributeString" },
434
+ "transform": { "$ref": "#/definitions/attributeString" },
435
+ "transform-origin": { "$ref": "#/definitions/attributeString" },
436
+ "type": { "$ref": "#/definitions/attributeString" },
437
+ "values": { "$ref": "#/definitions/attributeString" },
438
+ "viewBox": { "$ref": "#/definitions/attributeString" },
439
+ "visibility": { "$ref": "#/definitions/attributeString" },
440
+ "width": { "$ref": "#/definitions/attributeString" },
441
+ "word-spacing": { "$ref": "#/definitions/attributeString" },
442
+ "writing-mode": { "$ref": "#/definitions/attributeString" },
443
+ "x": { "$ref": "#/definitions/attributeString" },
444
+ "x1": { "$ref": "#/definitions/attributeString" },
445
+ "x2": { "$ref": "#/definitions/attributeString" },
446
+ "xChannelSelector": { "$ref": "#/definitions/attributeString" },
447
+ "y": { "$ref": "#/definitions/attributeString" },
448
+ "y1": { "$ref": "#/definitions/attributeString" },
449
+ "y2": { "$ref": "#/definitions/attributeString" },
450
+ "yChannelSelector": { "$ref": "#/definitions/attributeString" },
451
+ "z": { "$ref": "#/definitions/attributeString" }
454
452
  },
455
453
  "additionalProperties": false
456
454
  }
@@ -458,16 +456,16 @@
458
456
  "type": "object",
459
457
  "properties": {
460
458
  "$id": {
461
- "description": "A unique identifier for this style definition.",
462
- "type": "string"
459
+ "type": "string",
460
+ "maxLength": 256
463
461
  },
464
462
  "$schema": {
465
- "description": "The JSON Schema identifier for this document.",
466
- "type": "string"
463
+ "type": "string",
464
+ "maxLength": 256
467
465
  },
468
466
  "$comment": {
469
- "description": "An optional comment or description for this avatar style definition.",
470
- "type": "string"
467
+ "type": "string",
468
+ "maxLength": 4096
471
469
  },
472
470
  "meta": {
473
471
  "description": "Metadata about the avatar style, such as license information, creator details, and source references.",
@@ -479,7 +477,8 @@
479
477
  "properties": {
480
478
  "name": {
481
479
  "description": "The name of the license, e.g. `CC BY 4.0`.",
482
- "type": "string"
480
+ "type": "string",
481
+ "maxLength": 128
483
482
  },
484
483
  "url": {
485
484
  "description": "A link to the full license text.",
@@ -487,7 +486,8 @@
487
486
  },
488
487
  "text": {
489
488
  "description": "The full license text.",
490
- "type": "string"
489
+ "type": "string",
490
+ "maxLength": 32768
491
491
  }
492
492
  },
493
493
  "additionalProperties": false
@@ -498,7 +498,8 @@
498
498
  "properties": {
499
499
  "name": {
500
500
  "description": "The name of the creator.",
501
- "type": "string"
501
+ "type": "string",
502
+ "maxLength": 128
502
503
  },
503
504
  "url": {
504
505
  "description": "A link to the creator's website or profile.",
@@ -513,7 +514,8 @@
513
514
  "properties": {
514
515
  "name": {
515
516
  "description": "The name of the original source.",
516
- "type": "string"
517
+ "type": "string",
518
+ "maxLength": 128
517
519
  },
518
520
  "url": {
519
521
  "description": "A link to the original source.",
@@ -536,15 +538,16 @@
536
538
  "elements": {
537
539
  "description": "The list of SVG elements that make up the avatar.",
538
540
  "type": "array",
539
- "items": { "$ref": "#/definitions/element" }
541
+ "items": { "$ref": "#/definitions/element" },
542
+ "maxItems": 1024
540
543
  },
541
544
  "width": {
542
- "description": "The natural width of the avatar canvas in pixels. Must be at least 1.",
545
+ "description": "The natural width of the avatar canvas in pixels.",
543
546
  "type": "number",
544
547
  "minimum": 1
545
548
  },
546
549
  "height": {
547
- "description": "The natural height of the avatar canvas in pixels. Must be at least 1.",
550
+ "description": "The natural height of the avatar canvas in pixels.",
548
551
  "type": "number",
549
552
  "minimum": 1
550
553
  }
@@ -553,124 +556,108 @@
553
556
  "additionalProperties": false
554
557
  },
555
558
  "components": {
556
- "description": "Named, reusable SVG components. Each component defines a set of variants that the PRNG can select from at render time.",
559
+ "description": "Named, reusable SVG components. Each component defines a set of variants that the PRNG can select from at render time. Keys must be `camelCaseName` identifiers.",
557
560
  "type": "object",
558
- "patternProperties": {
559
- "^[a-z][a-zA-Z0-9]*$": {
560
- "description": "A named component definition.",
561
- "type": "object",
562
- "properties": {
563
- "width": {
564
- "description": "The natural width of the component canvas in pixels.",
565
- "type": "number",
566
- "minimum": 1
567
- },
568
- "height": {
569
- "description": "The natural height of the component canvas in pixels.",
570
- "type": "number",
571
- "minimum": 1
572
- },
573
- "probability": {
574
- "description": "The probability (0–100) that this component is rendered at all. A value of 0 means never, 100 means always.",
561
+ "propertyNames": { "$ref": "#/definitions/camelCaseName" },
562
+ "additionalProperties": {
563
+ "type": "object",
564
+ "properties": {
565
+ "width": {
566
+ "description": "The natural width of the component canvas in pixels.",
567
+ "type": "number",
568
+ "minimum": 1
569
+ },
570
+ "height": {
571
+ "description": "The natural height of the component canvas in pixels.",
572
+ "type": "number",
573
+ "minimum": 1
574
+ },
575
+ "probability": {
576
+ "description": "The probability, expressed as a percentage, that this component is rendered at all.",
577
+ "type": "number",
578
+ "minimum": 0,
579
+ "maximum": 100
580
+ },
581
+ "rotate": {
582
+ "description": "A rotation in degrees. A single value fixes the angle; two values define a range the PRNG picks from.",
583
+ "type": "array",
584
+ "items": {
575
585
  "type": "number",
576
- "minimum": 0,
577
- "maximum": 100
586
+ "minimum": -360,
587
+ "maximum": 360
578
588
  },
579
- "rotate": {
580
- "description": "A range of rotation angles in degrees the PRNG can choose from. Each value must be between -360 and 360.",
581
- "type": "array",
582
- "items": {
583
- "type": "number",
584
- "minimum": -360,
585
- "maximum": 360
586
- },
587
- "minItems": 1,
588
- "maxItems": 2
589
+ "minItems": 1,
590
+ "maxItems": 2
591
+ },
592
+ "translate": {
593
+ "description": "A positional translation applied to the component after placement. Values are interpreted as a percentage of the component's size.",
594
+ "type": "object",
595
+ "properties": {
596
+ "x": { "$ref": "#/definitions/translateValue" },
597
+ "y": { "$ref": "#/definitions/translateValue" }
589
598
  },
590
- "translate": {
591
- "description": "A positional translation applied to the component after placement.",
599
+ "additionalProperties": false
600
+ },
601
+ "variants": {
602
+ "description": "The available visual variants of this component. The PRNG selects one variant per render. Keys must be `camelCaseName` identifiers.",
603
+ "type": "object",
604
+ "propertyNames": { "$ref": "#/definitions/camelCaseName" },
605
+ "additionalProperties": {
592
606
  "type": "object",
593
607
  "properties": {
594
- "x": {
595
- "description": "A range of horizontal translation values the PRNG can choose from.",
608
+ "elements": {
609
+ "description": "The SVG elements that make up this variant.",
596
610
  "type": "array",
597
- "items": { "type": "number" },
598
- "minItems": 1,
599
- "maxItems": 2
611
+ "items": { "$ref": "#/definitions/element" },
612
+ "maxItems": 1024
600
613
  },
601
- "y": {
602
- "description": "A range of vertical translation values the PRNG can choose from.",
603
- "type": "array",
604
- "items": { "type": "number" },
605
- "minItems": 1,
606
- "maxItems": 2
614
+ "weight": {
615
+ "description": "A weight that influences how likely the PRNG is to select this variant. Higher values make the variant more likely. When omitted, defaults to 1 (equal weighting). A value of 0 means the variant is not selected unless all available variants have a weight of 0.",
616
+ "type": "number",
617
+ "minimum": 0,
618
+ "maximum": 1000000
607
619
  }
608
620
  },
621
+ "required": ["elements"],
609
622
  "additionalProperties": false
610
623
  },
611
- "variants": {
612
- "description": "The available visual variants of this component. The PRNG selects one variant per render.",
613
- "type": "object",
614
- "patternProperties": {
615
- "^[a-z][a-zA-Z0-9]*$": {
616
- "description": "A single variant of the component, containing its SVG element tree.",
617
- "type": "object",
618
- "properties": {
619
- "elements": {
620
- "description": "The SVG elements that make up this variant.",
621
- "type": "array",
622
- "items": { "$ref": "#/definitions/element" }
623
- },
624
- "weight": {
625
- "description": "A non-negative weight that influences how likely the PRNG is to select this variant. Higher values make the variant more likely. When omitted, defaults to 1 (equal weighting). A value of 0 means the variant is not selected by the PRNG unless all available variants have a weight of 0.",
626
- "type": "number",
627
- "minimum": 0
628
- }
629
- },
630
- "required": ["elements"],
631
- "additionalProperties": false
632
- }
633
- },
634
- "additionalProperties": false
635
- }
636
- },
637
- "required": ["width", "height", "variants"],
638
- "additionalProperties": false
639
- }
624
+ "maxProperties": 512
625
+ }
626
+ },
627
+ "required": ["width", "height", "variants"],
628
+ "additionalProperties": false
640
629
  },
641
- "additionalProperties": false
630
+ "maxProperties": 512
642
631
  },
643
632
  "colors": {
644
- "description": "Named color palettes used by the avatar. The PRNG selects colors from these groups at render time. Color groups can define constraints such as contrast or exclusion rules.",
633
+ "description": "Named color palettes used by the avatar. The PRNG selects colors from these groups at render time. Color groups can define constraints such as contrast or exclusion rules. Keys must be `camelCaseName` identifiers.",
645
634
  "type": "object",
646
- "patternProperties": {
647
- "^[a-z][a-zA-Z0-9]*$": {
648
- "description": "A named color.",
649
- "type": "object",
650
- "properties": {
651
- "values": {
652
- "description": "The list of hex color values the PRNG can choose from.",
653
- "type": "array",
654
- "items": {
655
- "type": "string",
656
- "pattern": "^#([a-fA-F0-9]{3}|[a-fA-F0-9]{4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$"
657
- }
658
- },
659
- "notEqualTo": {
660
- "description": "A list of other color names. The selected color value must differ from the color values selected in those colors.",
661
- "type": "array",
662
- "items": { "$ref": "#/definitions/identifier" }
663
- },
664
- "contrastTo": {
665
- "description": "The name of another color. When specified, the PRNG is not used for selection — instead, the color value with the highest contrast against the selected color value of the referenced color is chosen.",
666
- "$ref": "#/definitions/identifier"
667
- }
635
+ "propertyNames": { "$ref": "#/definitions/camelCaseName" },
636
+ "additionalProperties": {
637
+ "type": "object",
638
+ "properties": {
639
+ "values": {
640
+ "description": "The list of hex color values the PRNG can choose from.",
641
+ "type": "array",
642
+ "items": { "$ref": "#/definitions/hexColor" },
643
+ "minItems": 1,
644
+ "maxItems": 128
668
645
  },
669
- "required": ["values"],
670
- "additionalProperties": false
671
- }
646
+ "notEqualTo": {
647
+ "description": "A list of other color names. The selected color value must differ from the color values selected in those colors. The schema does not prevent cycles (e.g. `a` notEqualTo `b` and `b` notEqualTo `a`); renderers resolve palettes in definition order and must reject unsatisfiable configurations at load time.",
648
+ "type": "array",
649
+ "items": { "$ref": "#/definitions/colorName" },
650
+ "maxItems": 64
651
+ },
652
+ "contrastTo": {
653
+ "description": "The name of another color. When specified, the PRNG is not used for selection — instead, the color value with the highest contrast against the selected color value of the referenced color is chosen. The schema does not prevent cycles (e.g. `a` contrastTo `b` and `b` contrastTo `a`); renderers resolve palettes in definition order and must reject unsatisfiable configurations at load time.",
654
+ "$ref": "#/definitions/colorName"
655
+ }
656
+ },
657
+ "required": ["values"],
658
+ "additionalProperties": false
672
659
  },
673
- "additionalProperties": false
660
+ "maxProperties": 512
674
661
  }
675
662
  },
676
663
  "required": ["canvas"],