{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/stack-sh/theme/main/schemas/catalog.schema.json",
"title": "Stack Theme Catalog",
"description": "The portable source contract for Stack theme, icon, and deterministic font metric data.",
"type": "object",
"additionalProperties": false,
"required": [
"$schema",
"schemaVersion",
"catalogVersion",
"reservedThemeIds",
"fallbacks",
"fontMetrics",
"themes"
],
"properties": {
"$schema": {
"type": "string"
},
"schemaVersion": {
"const": "1.0"
},
"catalogVersion": {
"$ref": "#/$defs/semanticVersion"
},
"reservedThemeIds": {
"type": "array",
"items": {
"$ref": "#/$defs/identifier"
},
"uniqueItems": true
},
"fallbacks": {
"$ref": "#/$defs/catalogFallbacks"
},
"fontMetrics": {
"type": "array",
"items": {
"$ref": "#/$defs/fontMetrics"
}
},
"themes": {
"type": "array",
"items": {
"$ref": "#/$defs/theme"
}
}
},
"$defs": {
"semanticVersion": {
"type": "string",
"pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?(\\+[0-9A-Za-z.-]+)?$"
},
"identifier": {
"type": "string",
"pattern": "^[a-z][a-z0-9_-]{0,63}$"
},
"iconIdentifier": {
"type": "string",
"pattern": "^[a-z0-9][a-z0-9-]{0,63}$"
},
"catalogFallbacks": {
"type": "object",
"additionalProperties": false,
"required": ["missingThemeId", "missingIconId"],
"properties": {
"missingThemeId": { "$ref": "#/$defs/identifier" },
"missingIconId": { "$ref": "#/$defs/iconIdentifier" }
}
},
"relativePath": {
"type": "string",
"minLength": 1,
"maxLength": 240,
"pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$))[A-Za-z0-9._/-]+$"
},
"color": {
"type": "string",
"pattern": "^#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?$"
},
"paletteToken": {
"enum": [
"canvas",
"surface",
"surfaceMuted",
"text",
"textMuted",
"border",
"accent",
"danger",
"connector"
]
},
"palette": {
"type": "object",
"additionalProperties": false,
"required": [
"canvas",
"surface",
"surfaceMuted",
"text",
"textMuted",
"border",
"accent",
"danger",
"connector"
],
"properties": {
"canvas": { "$ref": "#/$defs/color" },
"surface": { "$ref": "#/$defs/color" },
"surfaceMuted": { "$ref": "#/$defs/color" },
"text": { "$ref": "#/$defs/color" },
"textMuted": { "$ref": "#/$defs/color" },
"border": { "$ref": "#/$defs/color" },
"accent": { "$ref": "#/$defs/color" },
"danger": { "$ref": "#/$defs/color" },
"connector": { "$ref": "#/$defs/color" }
}
},
"typography": {
"type": "object",
"additionalProperties": false,
"required": [
"fontMetricsId",
"nodeLabelSizeMilliPx",
"nodeDetailSizeMilliPx",
"groupLabelSizeMilliPx",
"edgeLabelSizeMilliPx",
"lineHeightPermille",
"labelWeight",
"detailWeight"
],
"properties": {
"fontMetricsId": { "$ref": "#/$defs/identifier" },
"nodeLabelSizeMilliPx": { "$ref": "#/$defs/positiveDimension" },
"nodeDetailSizeMilliPx": { "$ref": "#/$defs/positiveDimension" },
"groupLabelSizeMilliPx": { "$ref": "#/$defs/positiveDimension" },
"edgeLabelSizeMilliPx": { "$ref": "#/$defs/positiveDimension" },
"lineHeightPermille": {
"type": "integer",
"minimum": 1000,
"maximum": 3000
},
"labelWeight": { "$ref": "#/$defs/fontWeight" },
"detailWeight": { "$ref": "#/$defs/fontWeight" }
}
},
"positiveDimension": {
"type": "integer",
"minimum": 1,
"maximum": 1000000
},
"fontWeight": {
"type": "integer",
"minimum": 100,
"maximum": 900,
"multipleOf": 100
},
"nodeVisual": {
"type": "object",
"additionalProperties": false,
"required": [
"shape",
"fill",
"stroke",
"text",
"accent",
"cornerRadiusMilliPx",
"fallbackIconId"
],
"properties": {
"shape": {
"enum": [
"rounded-rectangle",
"capsule",
"circle",
"cylinder",
"hexagon"
]
},
"fill": { "$ref": "#/$defs/paletteToken" },
"stroke": { "$ref": "#/$defs/paletteToken" },
"text": { "$ref": "#/$defs/paletteToken" },
"accent": { "$ref": "#/$defs/paletteToken" },
"cornerRadiusMilliPx": {
"type": "integer",
"minimum": 0,
"maximum": 1000000
},
"fallbackIconId": { "$ref": "#/$defs/iconIdentifier" }
}
},
"nodeKindFallbacks": {
"type": "object",
"additionalProperties": false,
"required": [
"actor",
"client",
"service",
"function",
"worker",
"database",
"cache",
"queue",
"storage",
"external"
],
"properties": {
"actor": { "$ref": "#/$defs/nodeVisual" },
"client": { "$ref": "#/$defs/nodeVisual" },
"service": { "$ref": "#/$defs/nodeVisual" },
"function": { "$ref": "#/$defs/nodeVisual" },
"worker": { "$ref": "#/$defs/nodeVisual" },
"database": { "$ref": "#/$defs/nodeVisual" },
"cache": { "$ref": "#/$defs/nodeVisual" },
"queue": { "$ref": "#/$defs/nodeVisual" },
"storage": { "$ref": "#/$defs/nodeVisual" },
"external": { "$ref": "#/$defs/nodeVisual" }
}
},
"connectorStyle": {
"type": "object",
"additionalProperties": false,
"required": [
"stroke",
"text",
"labelBackground",
"widthMilliPx",
"arrowSizeMilliPx"
],
"properties": {
"stroke": { "$ref": "#/$defs/paletteToken" },
"text": { "$ref": "#/$defs/paletteToken" },
"labelBackground": { "$ref": "#/$defs/paletteToken" },
"widthMilliPx": { "$ref": "#/$defs/positiveDimension" },
"arrowSizeMilliPx": { "$ref": "#/$defs/positiveDimension" },
"dashMilliPx": {
"type": "array",
"items": { "$ref": "#/$defs/positiveDimension" },
"minItems": 2,
"maxItems": 8
}
}
},
"redistribution": {
"type": "object",
"additionalProperties": false,
"required": [
"cargo",
"npm",
"wasm",
"commercialApplications"
],
"properties": {
"cargo": { "type": "boolean" },
"npm": { "type": "boolean" },
"wasm": { "type": "boolean" },
"commercialApplications": { "type": "boolean" }
}
},
"provenance": {
"type": "object",
"additionalProperties": false,
"required": [
"sourceUrl",
"sourceRevision",
"copyright",
"licenseSpdx",
"licenseFile",
"modified",
"redistribution"
],
"properties": {
"sourceUrl": {
"type": "string",
"pattern": "^https://[^\\s]+$"
},
"sourceRevision": {
"type": "string",
"minLength": 1,
"maxLength": 160
},
"copyright": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"licenseSpdx": {
"type": "string",
"minLength": 1,
"maxLength": 120
},
"licenseFile": { "$ref": "#/$defs/relativePath" },
"modified": { "type": "boolean" },
"redistribution": { "$ref": "#/$defs/redistribution" }
}
},
"iconAsset": {
"type": "object",
"additionalProperties": false,
"required": ["path", "viewBox", "provenance"],
"properties": {
"path": { "$ref": "#/$defs/relativePath" },
"viewBox": {
"type": "array",
"prefixItems": [
{ "type": "integer" },
{ "type": "integer" },
{ "type": "integer", "minimum": 1 },
{ "type": "integer", "minimum": 1 }
],
"items": false,
"minItems": 4,
"maxItems": 4
},
"provenance": { "$ref": "#/$defs/provenance" }
}
},
"icon": {
"type": "object",
"additionalProperties": false,
"required": ["id", "subject", "asset"],
"properties": {
"id": { "$ref": "#/$defs/iconIdentifier" },
"subject": {
"type": "string",
"minLength": 1,
"maxLength": 120
},
"description": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"asset": { "$ref": "#/$defs/iconAsset" }
}
},
"theme": {
"type": "object",
"additionalProperties": false,
"required": [
"id",
"name",
"palette",
"typography",
"nodeKindFallbacks",
"connector",
"icons"
],
"properties": {
"id": { "$ref": "#/$defs/identifier" },
"name": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"description": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"palette": { "$ref": "#/$defs/palette" },
"typography": { "$ref": "#/$defs/typography" },
"nodeKindFallbacks": { "$ref": "#/$defs/nodeKindFallbacks" },
"connector": { "$ref": "#/$defs/connectorStyle" },
"icons": {
"type": "array",
"items": { "$ref": "#/$defs/icon" }
}
}
},
"glyphAdvances": {
"type": "object",
"propertyNames": {
"pattern": "^U\\+[0-9A-F]{4,6}$"
},
"additionalProperties": {
"type": "integer",
"minimum": 1,
"maximum": 32767
}
},
"fontMetrics": {
"type": "object",
"additionalProperties": false,
"required": [
"id",
"family",
"version",
"unitsPerEm",
"ascent",
"descent",
"lineGap",
"defaultAdvance",
"wideAdvance",
"wideRanges",
"glyphAdvances",
"provenance"
],
"properties": {
"id": { "$ref": "#/$defs/identifier" },
"family": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"version": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"unitsPerEm": {
"type": "integer",
"minimum": 16,
"maximum": 16384
},
"ascent": {
"type": "integer",
"minimum": 1,
"maximum": 32767
},
"descent": {
"type": "integer",
"minimum": -32768,
"maximum": 0
},
"lineGap": {
"type": "integer",
"minimum": 0,
"maximum": 32767
},
"defaultAdvance": {
"type": "integer",
"minimum": 1,
"maximum": 32767
},
"wideAdvance": {
"type": "integer",
"minimum": 1,
"maximum": 32767
},
"wideRanges": {
"type": "array",
"items": { "$ref": "#/$defs/unicodeRange" }
},
"glyphAdvances": { "$ref": "#/$defs/glyphAdvances" },
"provenance": { "$ref": "#/$defs/provenance" }
}
},
"unicodeRange": {
"type": "object",
"additionalProperties": false,
"required": ["start", "end"],
"properties": {
"start": {
"type": "string",
"pattern": "^U\\+[0-9A-F]{4,6}$"
},
"end": {
"type": "string",
"pattern": "^U\\+[0-9A-F]{4,6}$"
}
}
}
}
}