{
	"$schema": "https://json-schema.org/draft/2020-12/schema",
	"$id": "https://pchr.nick-glenn.com/pchr.schema.json",
	"properties": {
		"version": {
			"type": "integer",
			"maximum": 1,
			"minimum": 1,
			"description": "Format version. Currently 1."
		},
		"fps": {
			"type": "integer",
			"maximum": 65535,
			"minimum": 0,
			"description": "Playback frame rate."
		},
		"images": {
			"items": {
				"properties": {
					"name": {
						"type": "string",
						"description": "Image name."
					},
					"width": {
						"type": "integer",
						"maximum": 65535,
						"minimum": 0,
						"description": "Image width in pixels."
					},
					"height": {
						"type": "integer",
						"maximum": 65535,
						"minimum": 0,
						"description": "Image height in pixels."
					},
					"format": {
						"type": "string",
						"enum": [
							"png",
							"rgba8888"
						],
						"description": "Image data format: png (default) or rgba8888.",
						"default": "png"
					},
					"path": {
						"type": "string",
						"description": "Path to the image file (PNG), relative to the JSON file. pack decodes it to pixel data; unpack writes it."
					}
				},
				"additionalProperties": false,
				"type": "object",
				"required": [
					"name",
					"width",
					"height",
					"format",
					"path"
				],
				"description": "Image is an atlas image."
			},
			"type": "array",
			"description": "Atlas images referenced by meshes."
		},
		"bones": {
			"items": {
				"properties": {
					"name": {
						"type": "string",
						"description": "Bone name."
					},
					"parent": {
						"type": "integer",
						"maximum": 32767,
						"minimum": -1,
						"description": "Index of the parent bone, or -1 for a root bone."
					}
				},
				"additionalProperties": false,
				"type": "object",
				"required": [
					"name",
					"parent"
				],
				"description": "Bone is a single bone in the hierarchy."
			},
			"type": "array",
			"description": "Bone hierarchy in topological order (parents before children)."
		},
		"meshes": {
			"items": {
				"properties": {
					"name": {
						"type": "string",
						"description": "Mesh name."
					},
					"image": {
						"type": "integer",
						"maximum": 65535,
						"minimum": 0,
						"description": "Index into Images."
					},
					"vertices": {
						"items": {
							"properties": {
								"x": {
									"type": "number",
									"description": "X position in pixels (bind pose, world space)."
								},
								"y": {
									"type": "number",
									"description": "Y position in pixels (bind pose, world space)."
								},
								"u": {
									"type": "number",
									"description": "U texture coordinate (0 to 1)."
								},
								"v": {
									"type": "number",
									"description": "V texture coordinate (0 to 1)."
								},
								"influences": {
									"items": {
										"properties": {
											"bone": {
												"type": "integer",
												"maximum": 65535,
												"minimum": 0,
												"description": "Bone index."
											},
											"weight": {
												"type": "number",
												"description": "Influence weight."
											}
										},
										"additionalProperties": false,
										"type": "object",
										"required": [
											"bone",
											"weight"
										],
										"description": "Influence is a single bone's contribution to a vertex."
									},
									"type": "array",
									"maxItems": 4,
									"description": "Bone influences, at most MaxInfluences. Weights are stored as authored and are not renormalized."
								}
							},
							"additionalProperties": false,
							"type": "object",
							"required": [
								"x",
								"y",
								"u",
								"v",
								"influences"
							],
							"description": "Vertex is a single mesh vertex with its texture coordinate and skinning weights."
						},
						"type": "array",
						"description": "Mesh vertices."
					},
					"indices": {
						"items": {
							"type": "integer",
							"maximum": 65535,
							"minimum": 0
						},
						"type": "array",
						"description": "Triangle list, three indices per triangle. Length is a multiple of three."
					}
				},
				"additionalProperties": false,
				"type": "object",
				"required": [
					"name",
					"image",
					"vertices",
					"indices"
				],
				"description": "Mesh is a skinned mesh drawn from one atlas image."
			},
			"type": "array",
			"description": "Skinned meshes."
		},
		"animations": {
			"items": {
				"properties": {
					"name": {
						"type": "string",
						"description": "Animation name."
					},
					"loop": {
						"type": "boolean",
						"description": "Whether the animation loops."
					},
					"frames": {
						"items": {
							"items": {
								"properties": {
									"x": {
										"type": "number",
										"description": "X offset from parent (pixels, parent-local space). Root bones are in world space."
									},
									"y": {
										"type": "number",
										"description": "Y offset from parent (pixels, parent-local space). Root bones are in world space."
									},
									"rotation": {
										"type": "number",
										"description": "Rotation relative to parent, in degrees."
									},
									"scaleX": {
										"type": "number",
										"description": "Scale perpendicular to the bone."
									},
									"scaleY": {
										"type": "number",
										"description": "Scale along the bone (squash and stretch)."
									},
									"visible": {
										"type": "boolean",
										"description": "Whether this bone's meshes are visible."
									},
									"zOrder": {
										"type": "integer",
										"maximum": 32767,
										"minimum": -32768,
										"description": "Draw order (higher draws on top)."
									}
								},
								"additionalProperties": false,
								"type": "object",
								"required": [
									"x",
									"y",
									"rotation",
									"scaleX",
									"scaleY",
									"visible",
									"zOrder"
								],
								"description": "BoneTransform is a bone's pose within a single animation frame."
							},
							"type": "array"
						},
						"type": "array",
						"description": "Frames. Each frame is one transform per bone, in the same order as Bones."
					}
				},
				"additionalProperties": false,
				"type": "object",
				"required": [
					"name",
					"loop",
					"frames"
				],
				"description": "Animation is a sampled animation."
			},
			"type": "array",
			"description": "Sampled animations."
		}
	},
	"additionalProperties": false,
	"type": "object",
	"required": [
		"version",
		"fps",
		"images",
		"bones",
		"meshes",
		"animations"
	],
	"title": "PCHR JSON",
	"description": "JSON representation used by the pchr CLI to pack and unpack .pchr files. It is a tooling convenience for authoring and inspection and is not part of the binary format. Field names and ranges mirror the binary schema; the packed flags bytes are expressed here as booleans, and image pixel data is referenced by file path rather than embedded."
}
